postfix check walks the Postfix file tree, verifies permissions against the postfix-files manifest, and reports drift. It returns non-zero when it finds problems but does not stop or restart the running master. Safe to run in production at any time, which also makes the warnings easy to ignore.
What this means
The expected filesystem state is defined in postfix-files, which ships with the package and encodes ownership, group, and permission bits for every file and directory Postfix touches. When reality diverges from the manifest, you get a warning.
The warnings fall into distinct categories:
- Ownership and permission drift. Queue directories, daemon binaries, or the spool root have wrong owner, group, or mode bits. Common triggers: package updates that reset permissions, manual
chown/chmodoperations, filesystem restores that lose metadata, container builds that bake in incorrect ownership. - Setgid binary problems.
postdropandpostqueuemust be owned by grouppostdropwith the setgid bit set. Without this, local mail submission viasendmailfails becausepostdropcannot write to the maildrop queue directory. The failure shows up at runtime asmail_queue_enter: create file maildrop/...: Permission denied. - Configuration inconsistency. Undefined parameters referenced in master.cf (common with distro-packaged templates from Virtualmin or Plesk),
compatibility_levelmismatches that log warnings about changed defaults, and parameters whose values depend on other parameters that have drifted. - MAC denials (invisible to postfix check). SELinux or AppArmor policies blocking Postfix daemons from accessing files, sockets, or ports. These appear in
/var/log/audit/audit.logor kernel logs, not in mail.log.postfix checkhas no visibility into MAC policy.
The master keeps running through all of these. The risk is subtle, hard-to-diagnose failures: local mail stuck in maildrop because postdrop lost its setgid bit, TLS handshakes failing because compatibility defaults are stale, queues growing because a MAC policy update blocked access to a map file.
flowchart TD
A["postfix check returns warnings"] --> B{Category?}
B -->|Permission or ownership| C["Check postfix-files manifest"]
B -->|Setgid binary| D["Verify postdrop/postqueue group and mode"]
B -->|Undefined parameter| E["Define in main.cf or remove from master.cf"]
B -->|compatibility_level| F["Set level explicitly, then reload"]
B -->|Clean but mail broken| G["Check audit.log for MAC denials"]
C --> H["Run postfix set-permissions"]
D --> H
E --> I["postfix reload or restart"]
F --> I
G --> J["Set boolean or generate policy"]Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Permission drift on queue dirs | “warning: not owned by root: /var/spool/postfix/.” or subdirectory warnings | ls -ld /var/spool/postfix/ /var/spool/postfix/maildrop/ /var/spool/postfix/public/ |
| Setgid bit missing on postdrop | “warning: not set-gid or not owner+group+world executable: /usr/sbin/postdrop” | ls -l /usr/sbin/postdrop /usr/sbin/postqueue |
| Undefined parameter in master.cf | “postconf: warning: /etc/postfix/master.cf: undefined parameter: mua_sender_restrictions” | grep mua_sender_restrictions /etc/postfix/master.cf |
| compatibility_level too low | “warning: using backwards-compatible default” in mail.log | postconf -h compatibility_level |
| SELinux or AppArmor denial | Mail silently fails; no postfix check warning; nothing useful in mail.log | ausearch -m avc --start recent or dmesg |
| Stale config after reload | Parameter changed in main.cf but behavior unchanged | Whether the parameter requires restart, not reload |
Quick checks
All read-only. Safe for production.
# Run the check itself
postfix check 2>&1
# Verify queue directory permissions
# maildrop: drwx-wx--T (1730), public: drwx--x--- (710)
ls -ld /var/spool/postfix/maildrop/ /var/spool/postfix/public/
# Check setgid binaries (group execute should show 's', not 'x')
ls -l /usr/sbin/postdrop /usr/sbin/postqueue 2>/dev/null || ls -l /usr/bin/postdrop /usr/bin/postqueue
# List files in the spool not owned by postfix or root
find /var/spool/postfix -type f ! -user postfix ! -user root 2>/dev/null | head -20
# Check for setuid/setgid files in the queue (should be none)
find /var/spool/postfix -type f -perm /6000 2>/dev/null
# Show current compatibility_level
postconf -h compatibility_level
# Check for undefined parameter warnings during config expansion
postconf -n 2>&1 | grep -i warning
# Look for SELinux AVC denials related to postfix
ausearch -m avc --start recent 2>/dev/null | grep -i postfix | tail -20
# Verify master PID file consistency
cat /var/spool/postfix/pid/master.pid 2>/dev/null && ps -p "$(cat /var/spool/postfix/pid/master.pid)" -o pid,comm,lstart
How to diagnose
Run
postfix checkand capture all output. Warnings are prefixed withpostfix/postfix-script: warning:. Categorize into ownership, setgid, directory, or configuration issues.For ownership and permission warnings, compare reported paths against
postfix-files. The canonical expected permissions are:maildropowned by$mail_owner:$setgid_groupwith mode1730(drwx-wx--T), andpublicowned by$mail_owner:$setgid_groupwith mode710(drwx--x---).For setgid binary warnings, verify that
postdropandpostqueueare owned by grouppostdropwith the setgid bit set. Inls -loutput, the group execute position showss, notx.For undefined parameter warnings, grep master.cf for the references. Typical offenders are
mua_sender_restrictions,mua_client_restrictions, andmua_helo_restrictions, leftover template parameters from some distro packages. They appear during bothpostfix checkandpostconf -n.For compatibility_level warnings, check the current value. Postfix 3.0+ logs warnings when running with backwards-compatible defaults. Below level 1, defaults like
append_dot_mydomainchange fromyestonoand chroot defaults shift. Below 3.6, TLS fingerprint digests switch from MD5 to SHA256 and relay restriction ordering changes. ReviewCOMPATIBILITY_READMEfor the full list at each threshold.If
postfix checkis clean but mail is broken, check for MAC denials. SELinux AVC denials for Postfix daemons are logged to/var/log/audit/audit.log, not mail.log. AppArmor denials appear in kernel logs or the same audit log depending on distribution. This is the most commonly missed path because operators expect all Postfix problems in mail.log.Determine whether reload is sufficient or a full stop/start is needed. Most main.cf parameters take effect after
postfix reload. However,inet_interfaceschanges require a full stop and start. The master daemon does not pick up main.cf changes automatically, and master.cf changes are never applied without an explicit reload or restart. When uncertain,postfix stop && sleep 2 && postfix startis safer than reload because long-running daemons can retain cached config.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
postfix check exit code | Non-zero indicates drift or permission problems | Any non-zero return in automated checks |
| Maildrop queue depth | postdrop setgid failure causes mail to accumulate here | Files older than 10 minutes, or count above baseline |
| postdrop permission errors in mail.log | Confirms setgid or maildrop directory problem at runtime | “mail_queue_enter: create file maildrop/…: Permission denied” |
| compatibility_level warnings | Running with legacy defaults that may break TLS or relay behavior | “backwards-compatible default” entries in mail.log |
| SELinux AVC denial count | MAC policy silently blocking Postfix operations | Any postfix-related AVC denial in audit.log |
| Master restart frequency | Frequent restarts may indicate config instability or crash loops | Multiple “starting version” entries in short windows |
Fixes
Permission and ownership drift
The safest fix is postfix set-permissions, which restores ownership and permissions per the postfix-files manifest.
# Restore all Postfix file permissions from the manifest (non-disruptive)
postfix set-permissions
# Verify
postfix check
On Debian-based systems, postfix set-permissions may report warnings for files that the Debian package layout does not include. If warnings persist after set-permissions, fix specific paths manually.
For targeted manual fixes. These commands change ownership and permissions on live queue directories. Verify the paths match your installation before running.
# Fix spool root ownership
chown root:root /var/spool/postfix
# Fix queue directory ownership and permissions
chown postfix:postdrop /var/spool/postfix/maildrop
chmod 1730 /var/spool/postfix/maildrop
chown postfix:postdrop /var/spool/postfix/public
chmod 710 /var/spool/postfix/public
Setgid binary problems
# Fix postdrop and postqueue group ownership and setgid bit
chgrp postdrop /usr/sbin/postdrop /usr/sbin/postqueue
chmod g+s /usr/sbin/postdrop /usr/sbin/postqueue
# Verify (group execute should show 's')
ls -l /usr/sbin/postdrop /usr/sbin/postqueue
The binary path varies by distribution: /usr/sbin/postdrop on Debian/Ubuntu, /usr/bin/postdrop on others. Check with command -v postdrop.
Undefined parameters in master.cf
Either define the parameters in main.cf or remove the references from master.cf:
# Option 1: Define the parameters as empty (quick fix for template leftovers)
postconf -e 'mua_sender_restrictions ='
postconf -e 'mua_client_restrictions ='
postconf -e 'mua_helo_restrictions ='
# Option 2: Remove the references from master.cf (cleaner)
# Edit /etc/postfix/master.cf and remove or comment the offending lines
After either fix, run postfix check to confirm the warnings are gone, then postfix reload.
compatibility_level warnings
Set the compatibility level explicitly to silence the warnings and adopt current defaults:
# Check current level
postconf -h compatibility_level
# Set to your target level and reload
postconf -e compatibility_level=3.6
postfix reload
Review COMPATIBILITY_README before raising the level. Changed defaults may affect TLS fingerprint algorithms, relay restriction ordering, and chroot behavior. Test in staging first.
SELinux denials
If audit.log shows AVC denials for Postfix, review them first to confirm they are legitimate access needs, not an attack or misconfiguration.
# Search for recent Postfix AVC denials
ausearch -m avc --start recent | grep -i postfix
# Generate a custom policy module (review the .te file before applying)
audit2allow -a -M postfixCustom
semodule -i postfixCustom.pp
For Postfix needing write access to mail spool directories, the SELinux boolean allow_postfix_local_write_mail_spool may resolve the issue without a custom policy.
# Check current setting
getsebool allow_postfix_local_write_mail_spool
# Enable persistently
setsebool -P allow_postfix_local_write_mail_spool 1
Prevention
- Run
postfix checknightly via cron, then grep mail.log forreject|warning|error|fatal|panic. Alert on any non-empty output from either step. - Run
postfix checkafter every package update. Package updates are the most common source of permission drift, especially for setgid binaries where the package manager may reset group or mode bits. - Track file permissions in configuration management. If you manage Postfix with Ansible, Puppet, or Chef, declare the expected file ownership and mode bits so drift is corrected on the next run.
- Set
compatibility_levelexplicitly in main.cf. Never leave it at the default. This prevents surprise behavior changes and silences compatibility warnings that clutter logs. - Document reload vs restart per parameter in your runbooks. At minimum:
inet_interfacesrequires stop/start, master.cf service additions require reload. Preferpostfix stop && sleep 2 && postfix startwhen you need certainty that cached config is fully cleared. - Monitor audit.log for MAC denials alongside mail.log. SELinux and AppArmor denials for Postfix are invisible in standard mail logging. Include audit.log scanning in Postfix health checks, especially after OS-level policy updates.
How Netdata helps
- Per-second queue depth metrics let you correlate a
postfix checkwarning with immediate changes in maildrop or deferred queue size, confirming whether a permission problem is actually affecting mail flow or is purely cosmetic. - Mail log parsing surfaces postdrop permission errors, bounce rate spikes, and deferral patterns, so you see the runtime impact of configuration drift without manually grepping logs.
- Anomaly detection on queue growth rates catches the slow accumulation that follows a silent setgid failure or a stale config value, even when absolute thresholds have not been crossed.
- Filesystem monitoring (inodes, disk space, file descriptors) provides the surrounding context that distinguishes a Postfix permission problem from system-level resource exhaustion.






