452 4.3.1 Insufficient system storage, or a customer says mail from one partner stopped arriving this morning. You log in and everything looks normal: the site loads, the load average is quiet, and the big data volume is half empty. Postfix still refuses mail, because it does not look at the server as a whole. It looks at one filesystem only, the one that holds /var/spool/postfix.
On many VPS images that is simply the root filesystem. On servers built with separate partitions, it is a smaller /var, often sharing space with logs, the systemd journal, database files, and sometimes local mailboxes. When that filesystem gets tight, mail is the first service to notice.
What Postfix checks before it accepts a message
EHLO, then announces the envelope sender with MAIL FROM. That MAIL FROM step is where the Postfix SMTP server, smtpd, makes its storage decision.
At that point smtpd asks the kernel how much space is free on the filesystem containing queue_directory (by default /var/spool/postfix). This is a statvfs-style system call. The kernel answers from the filesystem's own accounting: block size, total blocks, free blocks, and the number of blocks available to non-root users. Postfix multiplies available blocks by block size, compares the result with its threshold, and if the number is too low it replies 452 4.3.1 Insufficient system storage and logs a reject.
A few consequences follow from this design. The transaction stops before RCPT TO and DATA, so no queue file is ever created and no message body is transferred. The check is cheap and runs on every new transaction, so Postfix starts refusing as soon as space drops and starts accepting again as soon as space comes back. No restart or reload is needed after you clean up.
The word available matters. Filesystems like ext4 usually keep a reserve of blocks that only root can use, set when the filesystem was created. Postfix's daemons run as the unprivileged postfix user, so that reserve does not count toward Postfix's free space. The Avail column in df -h shows the same non-root view, which is why it is the column to watch, not Size minus Used.
How queue_minfree sets the line
queue_minfree is the minimum free space in bytes the queue filesystem must have before smtpd accepts mail. Its default is 0, which sounds like no limit, but since Postfix 2.1 the SMTP server still refuses mail when free space falls below 1.5 times message_size_limit. The reasoning is simple: Postfix should always have room for at least one maximum-size message, plus some margin.
With the stock message_size_limit of 10240000 bytes, that floor works out to roughly 15 MB. On a modern disk that is almost nothing. By the time Postfix trips over it, the filesystem is effectively full and other services on /var are usually failing too.
That is why many admins set queue_minfree higher on purpose. A larger value (as an illustrative example, a few hundred megabytes or 1 GB on a busy relay) makes Postfix start answering with a temporary 4xx much earlier, while there is still room for queue files already in flight, log writes, and the database. The trade-off is that you refuse mail sooner. Because a 452 is a temporary error that senders retry, refusing early is usually safer than letting the disk fill to the last block while a message is half written. Two practical notes: a value lower than 1.5 x message_size_limit does not lower the floor, and if you raise message_size_limit for large attachments, the floor rises with it.
Inodes fail along a different path
statvfs call also returns inode counts, but the free-space check at MAIL FROM works in bytes. Inode exhaustion is a separate failure, and it is easy to miss because df -h can show gigabytes free.
Every queued message becomes at least one file. The cleanup daemon creates it under the incoming directory, and the queue manager later moves it to active and, if delivery fails, to deferred. Deferred messages also get small per-message log files under defer or bounce. A large backlog of undeliverable bounces or spam can therefore consume a lot of inodes on its own, and so can session files, cache directories, or millions of tiny files elsewhere on /var.
When no inodes are left, the kernel rejects file creation with ENOSPC, the same No space left on device error you get from a full disk. In that case smtpd passes its free-space check, accepts MAIL FROM, and the failure shows up later when cleanup cannot create the queue file. The sender typically sees a different temporary error, often mentioning a queue file write error, rather than the 4.3.1 storage message. The fix starts the same way, though: find what is filling /var. Confirming that a stuck queue is the cause is covered in How to Check If a Stuck Mail Queue Ran Your Server Out of Inodes.
What happens to mail while this is going on
sendmail drop mail into the maildrop directory on the same filesystem, so contact forms can fail quietly, and PHP's mail() may not surface the error to the visitor at all. If mailboxes live on the same /var, local delivery fails as well and messages pile up in deferred, consuming more of the space you are short of.
Checking /var the way Postfix sees it
BASH
# Where the queue lives and which thresholds apply
postconf queue_directory queue_minfree message_size_limit
# Free space and free inodes on the filesystem holding the queue
df -h $(postconf -h queue_directory)
df -i $(postconf -h queue_directory)
# Queue size summary (last line shows total size and request count)
postqueue -p | tail -n 1
# Recent storage-related rejects (log path depends on the distribution)
grep -E 'Insufficient system storage|not enough free space' /var/log/maillog /var/log/mail.log 2>/dev/null | tail -n 20journalctl against the Postfix unit and filter for the same strings; the unit name differs between distributions. In the logs you are looking for something shaped like this:
TEXT
# Illustrative output format
postfix/smtpd[2201]: warning: not enough free space in mail queue: 13107200 bytes < 1.5*message_size_limit 15360000 bytes
postfix/smtpd[2201]: NOQUEUE: reject: MAIL from mail.example.com[192.0.2.10]: 452 4.3.1 Insufficient system storage; proto=ESMTP helo=<mail.example.com>NOQUEUE confirms the point from earlier: the message was refused before a queue ID was ever assigned.
Freeing space without making it worse
/var is the problem, find what grew. These are also read-only:
BASH
# Largest directories on the same filesystem as /var
du -xh --max-depth=1 /var 2>/dev/null | sort -h | tail -n 15
# Files that were deleted but are still held open (space not yet released)
lsof +L1/var/lib, old backups or migration archives left in /var, and the mail queue itself. The second command catches a common trap: deleting a large log that a running process still has open does not free any space until that process closes or reopens the file.
A few cautions before you delete anything. Do not remove files under /var/spool/postfix by hand. Postfix tracks queue files internally, and pulling them out from under it can leave the queue inconsistent. If the queue is full of junk, review it first and remove specific messages with postsuper -d and the queue ID. Deleting queued mail is not reversible, so be sure it is really spam or dead bounces. For logs, prefer rotating or truncating through the normal logrotate or journald tooling over deleting active files. Database files under /var/lib/mysql should never be removed manually; purge binary logs or move data through the database itself.
When free space comes back above the threshold, Postfix starts accepting on the next transaction, and senders deliver on their next retry. Then check df -i again, because clearing a few large files fixes bytes but not inodes.
The practical habit is small. Add df -h and df -i against the queue directory to your routine checks and monitoring, alert on the Avail value with a margin well above queue_minfree, and consider raising queue_minfree so Postfix asks senders to wait while the rest of /var still has room to breathe. That catches the problem while it is still a full disk ticket, before it turns into a missing mail ticket.