A production Postfix server fails in ways that look healthy until they suddenly do not. Deferred queues fill with retrying messages while disk space appears fine. Inodes exhaust on a filesystem that df reports at 50% free. A single slow destination silently monopolizes the active queue, starving all other mail. Outbound TLS certificates expire on connections nobody monitors, and deliveries start deferring with cryptic SSL errors.
Four cumulative maturity levels: survival, operational, mature, expert. Walk through each as a gap analysis. Confirm you collect and alert on every signal at each level before moving up.
Assumes familiarity with Postfix architecture: the master daemon, the queue manager, the cleanup and delivery agents, and the queue directory under /var/spool/postfix/.
Monitoring maturity levels
flowchart TD
L1["L1 Survival
master, ports, disk, queue count"]
L2["L2 Operational
flow rates, queue depth, bounces, TLS, inodes, FDs"]
L3["L3 Mature
per-destination, filter health, composite patterns"]
L4["L4 Expert
qmgr pressure, age distribution, predictive modeling"]
L1 --> L2 --> L3 --> L4Each level is cumulative. The biggest jump in operational value is from Level 1 to Level 2: that is where you gain early warning instead of post-mortem detection.
Level 1: survival
Binary checks that tell you whether Postfix is alive and accepting mail. If any fail, you have a full outage.
| Signal | How to check | Alert when |
|---|---|---|
| Master process running | ps -p $(cat /var/spool/postfix/pid/master.pid) | PID file missing or references a dead or non-Postfix process |
| SMTP port 25 listening | ss -tlnp shows master bound on :25 | No socket on port 25 |
| Submission port 587 listening | ss -tlnp shows master bound on :587 | No socket on port 587 |
| SMTP greeting (220) | echo QUIT | nc -w 5 localhost 25 | head -1 | No greeting, timeout, or malformed banner |
| Queue not growing unbounded | find /var/spool/postfix/deferred -type f | wc -l | Total queue depth exceeds your delivery capacity in messages per hour |
| Disk space on queue partition | df -h /var/spool/postfix | Usage above 90% |
| Test send and receive | Send a test message via SMTP; confirm end-to-end delivery | Message not delivered within expected window |
Level 2: operational
Early warning of degradation before it becomes an outage. This is the baseline every production team should target.
| Signal | How to check | Alert when |
|---|---|---|
| Injection rate | Count client= log lines per time window | Drops to zero with expected traffic (listener or upstream failure) |
| Delivery rate | Count status=sent log lines per time window | Drops below 50% of baseline while injection continues |
| Deferred rate | Count status=deferred log lines | Ratio exceeds 20% of injection sustained |
| Deferred queue size | find /var/spool/postfix/deferred -type f | wc -l | Above 10,000 messages or sustained growth over 4 hours |
| Deferred queue growth rate | Track deferred count over fixed intervals | Sustained positive growth over 4 hours, or above 1,000 messages/hour with no plateau |
| Active queue vs limit | Compare ls /var/spool/postfix/active/ | wc -l against postconf -h qmgr_message_active_limit | Above 80% of limit (default 20,000) for more than 10 minutes |
| Bounce rate | Count status=bounced vs total delivery attempts | Above 1% sustained or sudden 10x increase from baseline |
| Inodes on queue filesystem | df -i /var/spool/postfix | Free inodes below 5%, or fewer than 10,000 free |
| File descriptor usage | Sum open FDs across Postfix processes, compare to ulimit -n | Above 80% of soft limit |
| SMTPD process utilization | Compare actual smtpd count to master.cf maxproc; scan logs for process-limit warnings | Repeated process-limit warnings for smtpd, qmgr, or cleanup |
| DNS resolver responsiveness | dig @resolver destination.com MX from the MTA host | Resolution failures or latency above 1 second |
| TLS certificate expiry | External check of SMTPD cert and outbound client cert chain | Within 30 days of expiry |
| Authentication failure rate | Count lines matching SASL.*authentication failed | Above 10x baseline from a single IP, or above 100/minute |
| Relay denial rate | Count lines matching relay access denied | Any successful unauthorized relay (zero tolerance) |
Level 3: mature
Root-cause identification, composite failure pattern detection, and resource pressure before it manifests as queue growth.
| Signal | Why it matters | Warning sign |
|---|---|---|
| Per-destination delivery and failure rates | One slow destination can monopolize the active queue and starve all others | Single domain accounting for a disproportionate share of deferred messages |
| Content filter and Milter response time | Filter backpressure grows the incoming queue while the active queue stays low | Filter p99 response above 5 seconds; incoming queue growing with active queue stable |
| Queue subsystem breakdown (maildrop, incoming, active, deferred, hold) | Distinguishes pickup failure, cleanup bottleneck, delivery stall, and filter backpressure | Maildrop accumulation indicates pickup failure; incoming growth indicates filter lag |
| Anvil connection state tracking | Reveals connection diversity and rate-limiting pressure | Single client exceeding 50 concurrent connections |
| Postscreen statistics | Shows zombie-blocking efficacy and passthrough load | High passthrough rate with low block rate means postscreen is ineffective |
| Relay recipient map consistency and latency | Stale maps cause accept-then-bounce; slow maps hang smtpd during RCPT | Map query time above 500ms for network-backed maps |
| Composite pattern detection | Catches queue gridlock, DNS failure, and filter cascade before they page | Multiple correlated signals trending wrong simultaneously |
| Process spawn rate | Excessive spawning indicates daemon crashes or resource exhaustion | Process-limit warnings increasing in frequency |
| Inode monitoring with trend alerting | Inode exhaustion is cliff-edge: no graceful degradation | Free inodes trending below 20% |
Level 4: expert
Deep instrumentation for high-volume relays, multi-instance deployments, or environments with strict deliverability SLAs.
| Signal | Why it matters |
|---|---|
Queue manager pressure (time postqueue -p) | Response time above 5 seconds indicates qmgr under stress |
| Per-transport throughput (smtp, local, virtual, pipe) | Different transports have very different capacity profiles |
| DNS lookup latency distribution | Tail latency on DNS causes smtpd to block on reverse lookups |
Message age distribution (qshape) | Reveals whether old messages are dominating, which raw counts hide |
| Milter protocol timing (DATA phase duration) | Identifies which Milter stage is the bottleneck |
| Multi-instance resource contention | One instance can starve another on shared hardware |
| Predictive queue growth modeling | Estimates hours until disk or inode exhaustion at current growth rate |
| TLS fingerprint tracking | Detects downgrade attacks or MITM interception |
Common blind spots
Gaps that show up repeatedly in post-incident reviews.
Inodes, not just disk space. Postfix creates one file per queued message plus metadata. “No space left on device” with df at 50% free means inode exhaustion. Monitor df -i on the queue filesystem. Degradation is cliff-edge.
Active queue saturation, not just deferred depth. When mail stops flowing, teams check the deferred queue and network. The actual constraint is often the active queue full of messages to one slow destination. Postfix does not prioritize messages by destination, so one destination returning timeouts or 4xx responses can fill active queue slots up to qmgr_message_active_limit (default 20,000). Most teams do not collect active queue size as a metric.
Growth rate, not just absolute size. A deferred queue of 5,000 messages that is shrinking is healthy. The same count growing at 2,000/hour is an incident in progress. Track the derivative of queue depth over time.
DNS as an unmonitored dependency. Postfix depends on DNS for MX lookup, reverse PTR verification, and DNSBL queries. DNS failure causes deferrals, not hard failures, so the system looks slow rather than broken. All destinations are affected equally, which distinguishes DNS failure from a single-destination problem. Monitor resolver latency and failure rate independently of Postfix.
Content filter health beyond process liveness. “Is Amavis running” is the wrong question. “Is Amavis responding in under 2 seconds” is the right one. The signal: incoming queue growing with a healthy active queue. Mail is accepted but cannot enter the delivery pipeline because the filter is the bottleneck.
File descriptors approaching ulimit. The default soft limit of 1024 is inadequate for production. Exhaustion manifests as “too many open files” errors and cascading connection failures. Monitor FD usage against the actual configured limit, not a fixed threshold.
TLS certificate expiry on outbound, not just inbound. Teams monitor the SMTPD certificate on port 25 but forget outbound client certificates or TLSA/DANE validation for destinations requiring mutual TLS. Outbound TLS failures cause silent deferrals. The failure surfaces as deferred queue growth with TLS-related deferral reasons in logs.
Bounce rate blindness. Bounces count as “sent” in simple delivery metrics. Sustained elevated bounce rates damage IP reputation and lead to blocklist listings within hours. Parse status=bounced explicitly.
Ignoring the maildrop queue. Local submissions from cron, monitoring scripts, and system daemons enter via maildrop and depend on the pickup daemon. Any file older than 10 minutes in maildrop is abnormal. Accumulation indicates pickup failure or a local mail generator producing a burst.
How Netdata helps
Netdata collects system and application metrics per second, which matters for Postfix because queue dynamics and delivery rates can shift in seconds rather than minutes.
- Process and socket monitoring: The process collector tracks master, qmgr, smtpd, and delivery agent counts. When smtpd approaches its
master.cfmaxproc, the process count chart shows it immediately alongside system FD usage. - Queue filesystem metrics: Disk space and inode usage are collected per-second per-mountpoint. Correlate inode exhaustion with deferred queue growth to confirm Postfix as the consumer driving depletion.
- System resource correlation: FD usage, CPU, memory, disk I/O, and network connections appear alongside Postfix metrics, so you can distinguish “Postfix is slow” from “the system under Postfix is saturated.”
- Postfix queue metrics: The Postfix collector reports queue depth via
postqueue. Log-derived rates (injection, delivery, deferred, bounce) require custom log parsing or an external tool feeding metrics into Netdata. - DNS resolver health: Systemd-resolved or BIND metrics on the same host let you correlate resolver latency spikes with deferred queue growth in a single dashboard.
- Anomaly detection: Anomaly flags on queue depth, delivery rate, and bounce rate catch deviations without manually tuned thresholds for every signal and destination.
Related guides
- How Postfix actually works in production: a mental model for operators
- Postfix monitoring maturity model: from survival to expert
- Postfix master process not running: the whole MTA is down
- Postfix not listening on port 25 or 587: connection refused
- postfix check warnings: configuration drift and permission problems
- Postfix mail flow: injection rate outpacing delivery rate
- Postfix active queue saturation: hitting qmgr_message_active_limit
- Postfix maildrop queue growing: pickup daemon and local submission failures
- Postfix queue message age: the delivery latency queue depth cannot show
- Postfix deferred queue growing: why mail piles up and how to drain it
- Postfix flushing and clearing the deferred queue: postqueue and postsuper
- Postfix Connection timed out: delivery deferrals to unreachable destinations






