Andrew Mercer
on this page

First move: scan the log for severity markers

grep -E '(warning|error|fatal|panic):' /var/log/maillog | less          # or /var/log/mail.log
journalctl -u postfix --since "1 hour ago" | grep -E '(warning|error|fatal|panic):'

The most important message is usually the earliest relevant one, not the last. Later errors are often consequences of an earlier root cause. Postfix's severity levels mean specific things:

Level Meaning
panic A bug in Postfix itself. Only a code fix resolves it. Report it with the log context
fatal Missing files, wrong permissions, or an invalid setting. You can fix it, but that process can't continue until you do
error An error condition. A process that hits too many in a row terminates itself to avoid a runaway loop
warning Non-fatal. Sometimes a real local misconfiguration (stale maps, deprecated parameters), sometimes noise from outside (broken remote DNS, quirky peers). Use judgment

Then check the basics before going deeper:

postfix check                # config syntax, file ownership and permissions
postconf -n                  # what's actually configured (typos show up here as warnings)
postconf 2>&1 >/dev/null     # any "unused parameter" or deprecation warnings
systemctl status postfix

Common errors and what they mean

fatal: open database /etc/aliases.db: No such file or directory

The compiled aliases database doesn't exist (or alias_maps points somewhere unexpected). Build it:

newaliases           # or: postalias /etc/aliases
systemctl restart postfix

On FreeBSD the aliases file lives at /etc/mail/aliases and Postfix's at /usr/local/etc/postfix/. Check postconf alias_maps for the real path. If the service doesn't start at all on a BSD system, also confirm postfix_enable="YES" in /etc/rc.conf.

warning: …/local: bad command startup -- throttling

This usually appears alongside the missing aliases database above. Fixing that clears this too. Otherwise, check the full log for the underlying fatal: from the local process.

warning: database /etc/postfix/xyz.db is older than source file /etc/postfix/xyz

You edited a map's source but didn't recompile it. It's the same fix for every map:

postmap /etc/postfix/xyz     # postalias for /etc/aliases
postfix reload

fatal: open database /etc/postfix/xyz.db: No such file or directory

A map is referenced in main.cf but was never compiled, or the source file doesn't exist. Create it (even empty) and run postmap.

unsupported dictionary type: hash

Your Postfix build has no Berkeley DB support (increasingly common on newer distributions). Switch the map to lmdb: or cdb: and recompile. postconf -m lists the supported types (see Overview and Architecture).

warning: TLS library problem: … SSL_CTX_use_PrivateKey_file … / key values mismatch

A stale or wrong key path, commonly left behind after a certificate was renamed or renewed, or a key that doesn't match the certificate. See TLS Encryption.

warning: TLS library problem … enabling PIX workarounds

Not your bug. The peer is behind a Cisco PIX/ASA with SMTP fixup enabled, and Postfix is compensating. It's informational.

warning: request to update table btree:/var/run/smtpd_tls_session_cache in non-postfix directory /var/run

The TLS session cache must live under Postfix's data_directory:

smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache

Recipient address rejected: User unknown in local recipient table / … in virtual mailbox table

The address doesn't exist in any map Postfix consults for that domain. Either it really doesn't exist (the rejection is doing its job, since a typo should bounce, not vanish), or a map is missing an entry. Check which address class the domain is in and query that map:

postmap -q [email protected] hash:/etc/postfix/virtual
postmap -q [email protected] proxy:mysql:/etc/postfix/sql/virtual_mailboxes.cf

Relay access denied (554 5.7.1)

The client isn't in mynetworks, didn't authenticate, and the recipient isn't a domain you accept. For your own users, they need to submit on 587/465 with authentication rather than port 25. If the client should be trusted, add it to mynetworks carefully.

SASL authentication failed (on your server) / SASL authentication failed; server … said: 535 (relaying out)

Inbound: check Dovecot's auth log (journalctl -u dovecot), and that smtpd_sasl_path points at the socket Dovecot actually created. Outbound to a smart host: wrong credentials, a sasl_passwd key that doesn't match relayhost exactly (brackets and port included), a forgotten postmap, or a provider requiring an app password or token. On RHEL-family systems, missing cyrus-sasl-plain gives no mechanism available.

warning: pipe flag 'D' requires dovecot_destination_recipient_limit = 1

You're delivering through Dovecot's LDA via a pipe service. Add the limit, or better, switch to LMTP (see Virtual Domains and Mailboxes):

dovecot_destination_recipient_limit = 1

connect to …[…]:25: Connection timed out (outbound)

Your ISP or cloud provider blocks outbound port 25, which is very common. Test with nc -vz gmail-smtp-in.l.google.com 25. The fix is a smart host on 587/465 (see Relaying Outbound Mail), or asking the provider to unblock it.

Host or domain name not found. Name service error for name=… type=AAAA: Host not found

AAAA lookups are failing or timing out on a host with flaky or absent IPv6. Stop Postfix using IPv6 if the host doesn't have it:

inet_protocols = ipv4

Or let Postfix fall back to /etc/hosts and NSS as well as DNS:

smtp_host_lookup = dns, native

send-mail: fatal: parameter inet_interfaces: no local interface found for ::1

inet_protocols includes IPv6, but the host has IPv6 disabled. Set inet_protocols = ipv4.

status=bounced (… said: 550 5.7.1 … SPF/DKIM/DMARC …) or 5.7.26

The receiver rejected your mail on authentication. Check your SPF include for the relay, DKIM signing, and DMARC alignment (see Email Authentication and Anti-Spam).

Multi-host LAN relay problems

These two errors are diagnosed on the receiving host, even though you first see them in the sending host's deferred queue:

relay=none, … status=deferred (connect to host[ip]:25: No route to host)

A firewall on the destination is rejecting inbound TCP/25. (Linux firewalls often answer with ICMP host prohibited, which appears as "No route to host".) Open it on the destination:

sudo firewall-cmd --permanent --add-service=smtp && sudo firewall-cmd --reload   # firewalld
sudo ufw allow from 192.0.2.0/24 to any port 25 proto tcp                         # ufw, LAN only
sudo nft add rule inet filter input tcp dport 25 ip saddr 192.0.2.0/24 accept     # nftables

relay=none, … status=deferred (connect to host[ip]:25: Connection refused)

The host is reachable, but nothing is listening on that address. This is almost always inet_interfaces = localhost (or loopback-only) on the destination:

inet_interfaces = all

inet_interfaces changes need a full systemctl restart postfix, not just a reload. Confirm with ss -tlnp | grep ':25 '. Also make sure the destination accepts mail for that domain, or trusts the sender in mynetworks if it should relay. A working delivery looks like this:

postfix/smtp[...]: ABC123: to=<[email protected]>, relay=desktop.lan.example[192.0.2.20]:25, delay=0.3, status=sent (250 2.0.0 Ok: queued as DEF456)
postfix/qmgr[...]: ABC123: removed

Verbose logging for one peer

When the normal log isn't enough, turn on verbose logging for just the problem host instead of the whole server:

debug_peer_list = 203.0.113.5          # or a hostname or domain
debug_peer_level = 2

postfix reload, reproduce the problem, then remove it again. The output is very large and can include message content. For TLS-specific detail, temporarily raise smtp_tls_loglevel or smtpd_tls_loglevel to 2.

General debugging workflow

  1. Find the earliest relevant error: grep -E '(warning|error|fatal|panic):', then follow the queue ID through the log.
  2. Validate the config: postfix check, postconf -n, and any deprecation warnings.
  3. Reproduce by hand: a manual SMTP session (telnet/nc, openssl s_client -starttls smtp, or swaks) separates "Postfix's accept/queue logic" from "the route or recipient that's failing".
  4. Check the maps: did you re-run postmap/postalias after the last edit? postmap -q the exact key. This is the single most common mistake.
  5. Check the outside world: DNS (dig MX, dig -x), reachability (nc -vz host 25), blocklists for your IP, and the peer's response text in postqueue -p.
  6. TLS problems: see TLS Encryption's troubleshooting section and posttls-finger.
  7. Two hosts you control: check both ends' logs. "No route to host" and "Connection refused" are fixed on the receiving end.