Emergency Response for a Full Disk on Linux
AI generated
$
/etc
Linux · Troubleshooting · Storage · Incident Response
Emergency Response for a Full Disk
reclaim space, find the cause, prevent recurrence

No space left on device in the middle of live production is one of the most unpleasant alerts there is, because MySQL, PHP sessions and logging can all fail at once. This article delivers the complete emergency workflow for a full disk: safely and quickly reclaim space, identify the actual largest consumer, and then make sure the incident does not repeat itself.

17 min read df · du · ncdu · lsof · logrotate Linux servers · Emergency operations

1. The first seconds: no panic deletion

When a disk is full and applications start crashing with errors like No space left on device, the impulse to immediately delete something is understandable, but dangerous. Deleting files at random without first knowing what they are needed for can corrupt a running database transaction, destroy an active backup, or remove a configuration file that is then missing. The first step with a full disk is therefore always observation before action.

A second common mistake is deleting a file that is still held open by a running process. On Linux, the operating system only releases the disk space of a deleted file once no process still holds an open file handle to it. If a large log file is deleted while a daemon is still writing to it, the disk space stays occupied until the process is restarted, and the full disk problem appears to persist unchanged, causing additional confusion.

2. df -h for the quick overview

The first concrete command with a full disk is df -h, which shows the usage of all mounted filesystems in human-readable units. It is important to check every line, not just the root partition: a separate mount for /var or /var/log can be full while / itself still has capacity, and vice versa. On Magento servers with a separate mount for pub/media in particular, this distinction is critical for the further search.

df -hT additionally shows the filesystem type, which helps in mixed setups with tmpfs, overlay mounts for Docker containers and regular ext4 or XFS partitions to distinguish real physical fullness from temporary RAM-backed mounts. A tmpfs mount that fills up has a different cause and different consequences than a full physical disk and must not be mixed up in the diagnosis.


# Step 1: check every mounted filesystem, not just root
df -hT
# Filesystem     Type   Size  Used Avail Use% Mounted on
# /dev/sda1      ext4    50G   49G  512M  99% /
# /dev/sdb1      xfs    200G  198G  1.8G  99% /var/lib/mysql
# tmpfs          tmpfs  8.0G  120M  7.9G   2% /tmp

# /var/lib/mysql is the actual bottleneck here, not root

In this example the actual problem is not the root partition but the separate mount for /var/lib/mysql, which is also nearly full. Anyone looking only at / overlooks the more critical partition and risks MySQL failing shortly after with a write error, even though the disk as a whole appeared to still have reserves.

3. Finding the biggest consumers with du and ncdu

Once it is clear which mount is actually full, the search for the biggest consumer follows. du -h --max-depth=1 /var | sort -rh shows the largest subdirectories at one level, sorted by size. The approach is repeated recursively: if /var/log is the largest consumer, du -h --max-depth=1 /var/log follows to narrow it down further within that directory, until the specific file or log is found.

For a faster, interactive search, ncdu is well suited, a text-based tool that scans a directory once and then makes it navigable via arrow keys, without repeated du calls. With an acutely full disk, this saves considerable time, because you click your way interactively from the root to the largest consumer instead of running a new command manually at every step.


# Recursive drill-down with du, one level at a time
du -h --max-depth=1 /var | sort -rh | head -10
# 18G   /var/log
# 4.2G  /var/lib/docker
# 1.1G  /var/cache

du -h --max-depth=1 /var/log | sort -rh | head -10
# 14G   /var/log/mysql
# 3.1G  /var/log/nginx

# Interactive drill-down — faster for repeated exploration
ncdu /var/log

4. Deleted but still open files via lsof

A frequently overlooked special case with a full disk: du shows occupied space, but large files can no longer be found in the filesystem directory tree because they were already deleted while a process still holds them open. The kernel only releases the disk space once the last file handle is closed, regardless of whether the file still exists from the filesystem's point of view.

lsof +L1 specifically lists files with a link count below one, i.e. deleted but still open files, together with their size and the holding process. This is extremely common with log rotation failures: a logrotate run renames or deletes a log file, but the writing daemon keeps writing merrily into the already deleted, but still space-occupying file through its old file handle.


# Find deleted-but-still-open files holding disk space
lsof +L1
# COMMAND   PID   USER   FD   TYPE DEVICE SIZE/OFF NLINK NODE NAME
# mysqld   1842   mysql   5w   REG  253,0  8.9G      0 4211 /var/log/mysql/slow.log (deleted)

# Reclaim the space by restarting or signaling the process to reopen its log file
kill -HUP 1842

The fix in this case is rarely to hard-kill the process. Many daemons, including mysqld and nginx, respond to SIGHUP by reopening their log file handles, which releases the deleted but blocked file immediately, without restarting the service. This technique is at the core of any emergency workflow for a full disk, because it often frees several gigabytes within seconds without risking an outage in production.

5. Safe cleanup: logs, caches, temp files

After identifying the biggest consumer, the actual cleanup follows, but here too the rule applies: targeted rather than blanket. Old, already rotated log files under /var/log with extensions like .1, .gz or .old can generally be compressed or deleted without risk, because logrotate has already marked them as complete. Composer and npm caches, temporary Docker build layers, and outdated kernel images on apt-based systems are further common, low-risk candidates for quick cleanup with a full disk.

Caution is required with anything currently being written: active session files under /var/lib/php/sessions, running backup archives, or database binlogs still needed for replication. Before any deletion on a production system, a quick lsof check on the target directory is worthwhile to make sure no active process is currently using exactly that file.


# Safe, low-risk cleanup candidates on most Debian/Ubuntu servers
apt-get clean                                    # cached .deb packages
journalctl --vacuum-size=200M                    # cap systemd journal size
find /var/log -name "*.gz" -mtime +30 -delete    # old rotated logs
docker system prune -af --volumes                # unused Docker images/layers
composer clear-cache

6. When df still shows free space: inode exhaustion

A lesser-known special case of a full disk: df -h shows free space, yet the system still reports No space left on device. In this case it is not byte-level disk space that is exhausted, but the number of available inodes. Every filesystem reserves a fixed number of inodes at creation time, and every file, no matter how small, consumes exactly one. Directories with millions of tiny files, such as PHP session files or mail queues, exhaust inodes long before space itself runs low.

df -i shows inode usage analogous to df -h for bytes. If IUse% reads 100 percent there, the number of files must be reduced, not their size. The fix is usually to consistently clean up stale session files or queue entries; long-term, a separate filesystem for such directories with an appropriately sized inode count at reformatting time helps.

7. Database special case: binlogs and tablespaces

On MySQL and MariaDB servers, a particularly common cause of a full disk is an unboundedly growing binlog history. If expire_logs_days or binlog_expire_logs_seconds is not set, binlog files accumulate indefinitely, especially when a replication slave has been offline for a while and the master retains logs for it. PURGE BINARY LOGS BEFORE with a concrete date cleans up here in a targeted way, without endangering active replication.

A second database-specific case is InnoDB tablespace growth from deleted but not reclaimed data regions. Without innodb_file_per_table, all tables grow inside a shared ibdata1 file that does not automatically shrink after large tables are dropped. A clean dump-and-reimport into a freshly created database with the per-table file option enabled is often the only sustainable fix for a recurring full disk.

8. Prevention: monitoring, quotas, log rotation

The best way to deal with a full disk is to never let it happen in the first place. A monitoring alert at 80 percent usage gives enough lead time to act calmly instead of improvising during an acute full state. Tools like Prometheus with the node_exporter, or a simple cron script with df evaluation and email dispatch, already fulfill this purpose without much effort.

A properly configured logrotate rule with maxsize, rotate and compress prevents individual log files from growing without bound. For directories with user-generated data, for example upload folders in Magento, filesystem quotas limit the maximum possible consumption per user or directory and prevent a single misbehaving process from filling the entire disk.

9. Causes and remedies compared

The following table maps the most common causes of a full disk to the appropriate immediate remedy and the long-term prevention step, so that the right trail is followed quickly during an emergency.

Cause Immediate remedy Long-term prevention
Unrotated logs du, compress/delete old logs Configure logrotate with maxsize
Deleted, open file lsof +L1, SIGHUP the process Test log rotation with copytruncate
Inode exhaustion df -i, clean up small files Separate mount with more inodes
Growing binlogs PURGE BINARY LOGS BEFORE Set binlog_expire_logs_seconds
Docker layers, images docker system prune -af Regular cron-based cleanup
Full PHP session storage find /var/lib/php/sessions -mmin +1440 -delete Set session.gc_maxlifetime correctly
Growing Elasticsearch indices Delete old indices via ILM Configure Index Lifecycle Management

The table makes it clear: a full disk rarely has a single cause. In practice, several of the listed factors often combine, for example unrotated Nginx logs together with growing MySQL binlogs, which is why a complete diagnosis should always go through every layer from filesystem to application.

Mironsoft

Server monitoring, storage prevention and incident response

Never be surprised by a full disk again?

We set up monitoring with timely alerts, configure log rotation and database housekeeping, and are available for fast emergency diagnosis whenever an acute full state occurs.

Storage monitoring

Early warning at 80 percent usage instead of a surprise at 100 percent

Log and DB housekeeping

Cleanly configure logrotate, binlog rotation and Docker cleanup

Emergency support

Fast, low-risk recovery during an acute full-disk incident

10. Summary

A full disk demands a fixed order of operations: first observe with df -hT, then narrow down with du or ncdu, remembering to check deleted but open files with lsof +L1, and only then delete in a controlled manner. Special cases like inode exhaustion and growing database binlogs require their own diagnostic paths that a plain df -h look does not reveal.

The most sustainable protection against a recurring full disk is prevention: timely monitoring at 80 percent usage, consistent log rotation, and automated database housekeeping jobs. Anyone who sets up these three building blocks properly once turns a recurring emergency into a plannable maintenance topic.

Full disk on Linux — the essentials at a glance

First overview

df -hT shows all mounts including type, never check the root partition alone.

Finding the culprit

du --max-depth=1 recursively or ncdu interactively for a fast narrow-down.

Hidden traps

lsof +L1 for deleted open files, df -i for inode exhaustion.

Prevention

Monitoring at 80%, logrotate with maxsize, binlog expiry and Docker cleanup.

11. FAQ: Full disk on Linux

1First command with a full disk?
df -hT for all mounts, never check the root partition alone.
2Why no panic deletion?
Can corrupt running transactions, backups or configs, observe first.
3du shows less than occupied?
Deleted but held-open files are invisible to du, lsof +L1 finds them.
4Reclaim space of a deleted open file?
SIGHUP to the process so it reopens the file handle, usually no restart needed.
5df shows space, still full?
Likely inode exhaustion, check df -i, often caused by millions of small files.
6Limit MySQL binlogs?
Set binlog_expire_logs_seconds, in acute cases use PURGE BINARY LOGS BEFORE.
7What is safe to delete?
Rotated logs, apt-get clean, docker system prune, Composer/npm caches.
8Fastest way to find the culprit?
ncdu scans once and allows interactive navigation, faster than repeated du.
9Prevent recurrence permanently?
Monitoring at 80%, logrotate with maxsize, binlog expiry, regular Docker cleanup.
10Why doesn't ibdata1 shrink?
Without innodb_file_per_table all tables share one file, dump-and-reimport helps.