A deferred queue is growing and you need to act. The difference between using postqueue and postsuper well and badly is the difference between controlled recovery and a self-inflicted stampede.
Postfix holds messages that failed temporary delivery in the deferred queue for retry with exponential backoff. The retry scheduler uses minimal_backoff_time (default 300s) and maximal_backoff_time (default 4000s) to space out attempts. When you intervene manually, you are overriding that scheduler. Sometimes that is the right call, like when a relay host has recovered and the mail is now deliverable. Often it is not.
The Postfix QSHAPE_README is explicit: flushing the entire deferred queue is “more than likely counter-productive, and typically makes the congestion worse.” A full flush bypasses the cool-off throttling that prevents all deferred messages from hitting the active queue at once. If most of those messages are still undeliverable, you have turned a slow-burning queue problem into an active queue stampede.
This guide covers the recovery procedures: when to flush selectively, when to hold mail for a specific destination, when to requeue, when to delete, and how to target one bad destination without touching the rest.
Prerequisites
You need root or appropriate sudo access. Both postqueue and postsuper are privileged operations. You also need:
- Postfix running and responsive. Verify with
postqueue -preturning in under 5 seconds. If the queue manager is hung, queue operations will block. - Enough free inodes on the queue filesystem. Large queue operations create and remove many files. Check with
df -i /var/spool/postfix. - Knowledge of your queue layout. Postfix stores queues under
/var/spool/postfix/:deferred/,active/,incoming/,hold/,maildrop/, andcorrupt/. Deferred messages are further distributed across hash subdirectories (deferred/0/,deferred/1/, etc.). - qshape installed if you plan to use it. On Debian/Ubuntu it is in the
postfix-perl-scriptspackage; on RHEL derivatives it ships with the mainpostfixpackage.
Assess the queue before acting
Before running any mutation command, understand what is in the queue and why it is stuck. Blind flushing is the most common operator mistake.
# Overall queue summary
postqueue -p | tail -1
# JSON output (Postfix 3.1+) for scripting
postqueue -j | head -20
# Deferred queue file count
find /var/spool/postfix/deferred -type f | wc -l
The best diagnostic tool for a large deferred queue is qshape(1). It shows age distribution per destination domain, which tells you both how long mail has been stuck and which destinations are consuming queue slots. It displays intermediate results after every 1000 messages when output is a terminal, so it remains usable even on very large queues.
# Shape of deferred queue by destination domain
qshape deferred | head -20
# Shape of active queue
qshape active | head -20
Identify the deferral reasons in your logs:
# Top deferred destination domains
grep 'status=deferred' /var/log/mail.log \
| awk -F'to=<|>,' '{print $2}' | cut -d@ -f2 \
| sort | uniq -c | sort -rn | head
# Recent deferral messages (read the parenthesized reason)
grep 'status=deferred' /var/log/mail.log | tail -10
If one destination dominates the deferred queue, that is your target for selective operations. If all destinations are deferred with DNS errors, your problem is DNS, not the queue. Fix the root cause before flushing.
flowchart TD
A["Assess queue: qshape + postqueue -p"] --> B{"Root cause fixed?"}
B -- No --> C["Hold affected mail: postsuper -h"]
B -- Yes --> D{"Most mail now deliverable?"}
D -- Yes --> E["Flush selectively, then full if needed"]
D -- No --> F{"Mail is spam or invalid?"}
F -- Yes --> G["Delete selectively: postsuper -d"]
F -- No --> H["Hold and investigate"]
E --> I["Monitor active queue + delivery rate"]
G --> I
H --> IHold and release: freezing mail safely
Holding mail moves it out of the delivery pipeline without deleting it. This is the safest intervention when a destination is down and you do not want its mail consuming active queue slots or generating retry traffic.
# Hold a single message by queue ID
postsuper -h QUEUE_ID
# Hold all messages (every queue)
postsuper -h ALL
# Release a held message back into the normal queue
postsuper -H QUEUE_ID
# Release all held messages
postsuper -H ALL
Held messages appear in postqueue -p output with an ! appended to the queue ID. They sit in the hold/ queue and are not retried until you release them. This is reversible and non-destructive.
Use postsuper -h ALL sparingly on large queues. It is an O(n) operation that iterates every queue file. On a queue with hundreds of thousands of messages, expect it to take minutes and generate significant disk I/O.
Flush: forcing deferred mail to retry
Flushing tells the queue manager to attempt immediate delivery of deferred messages, bypassing the normal backoff schedule.
Selective flush by queue ID (Postfix 2.4+):
# Schedule immediate delivery of one message
postqueue -i QUEUE_ID
This is the safest flush operation. Use it when you have confirmed that a specific message is now deliverable, for example after fixing a DNS issue or after a relay host recovers.
Selective flush by site (requires fast_flush_domains configuration):
# Fast-flush mail for a specific destination
postqueue -s example.com
This flushes only mail destined for the specified site. It requires that the destination is listed in fast_flush_domains. Most operators never configure this, so verify before relying on it.
Full flush (use with caution):
# Force retry of ALL deferred mail
postqueue -f
The postqueue(1) man page warns: “flushing undeliverable mail frequently will result in poor delivery performance of all other mail.” A full flush bypasses the cool-off throttling. Every deferred message becomes eligible for the active queue simultaneously. If the active queue hits qmgr_message_active_limit (default 20,000), delivery of all mail, including to healthy destinations, stalls.
Only use postqueue -f when you expect that most of the deferred content has recently become deliverable. The textbook case is a relay host that was down for maintenance and is now back. If only 10% of deferred mail is deliverable and 90% will fail again, you have made the problem worse.
Requeue: putting mail back through cleanup
Requeuing moves a message back to the maildrop queue, where it re-enters the pipeline through cleanup. This re-applies address rewriting and content_filter processing.
# Requeue a single message
postsuper -r QUEUE_ID
# Requeue all messages
postsuper -r ALL
Use requeue when you have changed configuration that affects how messages should be processed: new transport_maps, new content_filter, or changed address rewriting rules.
Important limitation: requeued messages are not subjected to smtpd_milters or non_smtpd_milters. If mail passed through an external content filter and you requeue it, Milter applications that depend on original SMTP connection state will produce incorrect results. This is documented in the postsuper(1) man page.
On large queues, postsuper -r ALL is expensive. It moves every queue file back through the cleanup daemon, which is single-threaded. Sequence it in batches if the queue is large.
Delete: removing mail permanently
Deletion is irreversible. Read this section carefully before running anything.
# Delete a single message by queue ID
postsuper -d QUEUE_ID
# Delete messages by reading queue IDs from stdin
postsuper -d -
# Delete ALL messages from ALL queues (hold, incoming, active, deferred)
postsuper -d ALL
# Delete ALL messages from deferred queue only
postsuper -d ALL deferred
The word ALL must be uppercase. postsuper -d ALL deletes from every queue. postsuper -d ALL deferred restricts the deletion to the deferred queue. Always prefer the scoped form.
Queue ID reuse race condition: Postfix queue IDs are reused (always with Postfix 2.8 and earlier; with Postfix 2.9+ when enable_long_queue_ids=no, which is the default). There is a small possibility, approximately 1 in 2^15, that postsuper -d deletes the wrong message file when executed while Postfix is actively delivering mail. The man page documents this explicitly. For critical single-message deletions during high delivery volume, consider holding the message first (postsuper -h), verifying, then deleting.
Reading queue IDs from stdin lets you delete selectively without typing each ID:
# Delete all bounce messages from MAILER-DAEMON
mailq | grep 'MAILER-DAEMON' \
| awk '{print $1}' | sed 's/[!*]$//' \
| postsuper -d -
The sed 's/[!*]$//' step is necessary because postqueue -p and mailq append status characters to queue IDs: * for active messages, ! for held messages. Without stripping them, postsuper receives invalid IDs and silently skips them.
Forced expiration (Postfix 3.5+) offers an alternative to straight deletion. Instead of silently removing a message, force-expiration generates a bounce or DSN to the sender:
# Force-expire a message (generates bounce/DSN)
postsuper -e QUEUE_ID
Expired messages in postqueue -p output show a # status character.
Targeting one bad destination
The most common real-world scenario: one destination is slow, rate-limiting, or down. Its mail is monopolizing active queue slots. You need to quarantine that destination’s mail without touching the rest.
Step 1: Hold mail for the problem destination.
# Find and hold mail to a specific domain
find /var/spool/postfix/deferred -type f \
-exec grep -l '@problem-domain\.com' {} \; \
| awk -F/ '{print $NF}' \
| postsuper -h -
The awk -F/ '{print $NF}' extracts the queue ID (the filename) from the full path returned by find. Deferred queue files are stored in hash subdirectories, so find returns paths like /var/spool/postfix/deferred/0/A1B2C3D4E5F.
Note: grep -l matches against the raw queue file content, so it may match messages that merely mention the domain in headers or body, not just the envelope recipient. For precise recipient matching on large queues, parse postqueue -p output instead, though that is slower.
Step 2: Fix the underlying issue. Wait for the destination to recover, let a rate limit expire, or restore network connectivity.
Step 3: Release the held mail.
# Release held mail for the problem domain
find /var/spool/postfix/hold -type f \
-exec grep -l '@problem-domain\.com' {} \; \
| awk -F/ '{print $NF}' \
| postsuper -H -
Step 4: Flush selectively if appropriate.
# Flush only the just-released messages
find /var/spool/postfix/deferred -type f \
-exec grep -l '@problem-domain\.com' {} \; \
| awk -F/ '{print $NF}' \
| while read id; do postqueue -i "$id"; done
This targeted approach avoids stampeding all destinations and gives you control over the retry rate. If the volume is large, consider adding a small sleep between postqueue -i calls to pace the active queue refill.
Verifying the result
After any queue operation, verify the effect before walking away:
# Queue summary
postqueue -p | tail -1
# Active queue size (should not be at qmgr_message_active_limit)
find /var/spool/postfix/active -type f | wc -l
# Current active limit
postconf -h qmgr_message_active_limit
# Delivery rate in the last 2 minutes
grep "$(date -d '2 minutes ago' '+%b %e %H:%M')" /var/log/mail.log \
| grep -c 'status=sent'
If you flushed and the active queue is pinned at qmgr_message_active_limit, the flush overwhelmed the system. Consider holding some mail back to relieve active queue pressure.
Common pitfalls
Flushing before fixing the root cause. The most common and most damaging mistake. If mail is deferred because DNS is broken, flushing will not deliver it. It will fill the active queue with messages that immediately fail again, blocking healthy mail. Fix the root cause first.
Ignoring the active queue limit. A full flush can push the active queue to qmgr_message_active_limit (default 20,000). Once full, no new deliveries can be scheduled regardless of destination health. Monitor the active queue size during and after any flush.
Running postsuper on huge queues without batching. These commands are O(n): they scan the entire queue directory structure. On a queue with hundreds of thousands of messages, postsuper -r ALL or postsuper -h ALL can take many minutes and generate heavy disk I/O. Sequence operations in batches and monitor inode usage during execution.
Forgetting that postsuper -r skips milters. If your pipeline depends on Milter processing (DKIM signing, policy daemons), requeued mail will not pass through them. This can produce unsigned or unvalidated mail.
Deleting with postsuper -d ALL by accident. This command is irreversible and deletes from all queues. Always use postsuper -d ALL deferred if you only want to clear the deferred queue. Double-check the command before pressing enter.
Signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
| Deferred queue growth rate | Sustained growth means delivery failures exceed retry success | Positive growth sustained over 4 hours |
| Active queue size vs limit | Active queue at limit means no new deliveries can start | Above 80% of qmgr_message_active_limit |
| Delivery rate after flush | Confirms whether the flush helped or hurt | Delivery rate flat or declining after flush |
| Queue filesystem inodes | Bulk queue operations create and remove many files | Free inodes below 10% |
| Deferral reason distribution | Identifies whether one destination or all destinations are affected | Single destination accounting for majority of deferrals |
| Postqueue response time | Slow response indicates queue manager under pressure | postqueue -p taking more than 5 seconds |
How Netdata helps
- Per-second queue size metrics let you see the immediate effect of a flush, hold, or delete within seconds. You can watch the deferred queue shrink and the active queue fill in real time, not minutes later.
- Active queue saturation correlation is critical during a flush. Netdata surfaces active queue size against
qmgr_message_active_limitso you can catch a stampede before it blocks all delivery. - Injection vs delivery rate shows whether your flush actually increased outbound deliveries or just moved mail from deferred to active where it stalled again.
- Deferral reason tracking from logs identifies the specific destination or error code driving queue growth, which tells you whether to flush, hold, or fix something upstream.
- Disk I/O and inode pressure during bulk postsuper operations helps you avoid secondary failures caused by the cleanup itself.
Related guides
- Postfix active queue saturation: hitting qmgr_message_active_limit
- postfix check warnings: configuration drift and permission problems
- How Postfix actually works in production: a mental model for operators
- Postfix mail flow: injection rate outpacing delivery rate
- Postfix master process not running: the whole MTA is down
- Postfix monitoring checklist: the signals every production mail server needs
- Postfix monitoring maturity model: from survival to expert
- Postfix not listening on port 25 or 587: connection refused






