“Connection refused” on port 25 or 587 means no process on the host is completing the TCP handshake on that port. This is distinct from a timeout, where something accepts the SYN but never responds. “Refused” means either no process is listening, or the kernel is actively rejecting the connection.
The most common real-world causes: the master process is down, Postfix is bound to loopback only, the smtpd process pool is exhausted, or a firewall is intercepting traffic before Postfix sees it. Less common but worth checking: inet_protocols mismatch on IPv6-disabled hosts, port conflicts with other MTAs, and postscreen handoff failures.
What this means
For Postfix, “connection refused” has two primary failure shapes:
No socket at all: The master process is not running, or it failed to bind the configured port due to an interface mismatch, IPv6 issue, or port conflict.
Socket present but not serving: Postfix or postscreen is listening, but all smtpd workers are consumed by slow clients or hung on DNS or milter lookups. New connections are refused because master cannot spawn another smtpd within the maxproc limit.
A third pattern that looks like “Postfix not listening” is a firewall or SYN-cookie layer intercepting traffic. The socket is present and Postfix is healthy, but external clients cannot reach it. Always test both locally and remotely.
flowchart TD
A["Connection refused
on port 25 or 587"] --> B{"Socket present?"}
B -->|"No"| C{"Master process running?"}
B -->|"Yes"| D{"220 greeting received?"}
C -->|"No"| E["Master down or
failed to bind"]
C -->|"Yes"| F["Interface or protocol
mismatch"]
D -->|"No"| G["smtpd exhausted
or hung"]
D -->|"Yes"| H{"Works locally,
fails remotely?"}
H -->|"Yes"| I["Firewall or
ISP block"]
H -->|"No"| J["Postscreen handoff
or greeting mismatch"]Common causes
| Cause | What it looks like | First thing to check |
|---|---|---|
| Master process not running | No socket on port 25 or 587; postfix status reports not running | cat /var/spool/postfix/pid/master.pid and verify PID |
| inet_interfaces bound to loopback | Socket on 127.0.0.1:25 only; external connections refused | postconf -h inet_interfaces |
| inet_protocols mismatch (IPv6 disabled) | Postfix logs “cannot assign requested address”; no socket bound | postconf -h inet_protocols vs host IPv6 state |
| master.cf explicit IP binding | Postfix bound to 127.0.0.1 regardless of inet_interfaces = all | postconf -M smtp/inet |
| smtpd maxproc exhaustion | Socket present but no 220 greeting; “to limit” in logs | ps aux | grep smtpd | grep -v grep | wc -l vs maxproc |
| Postscreen handoff failure | Postscreen answers on 25 but smtpd pass fails | Test both postscreen and direct smtpd paths |
| Firewall or SYN-cookie interception | Local connection works; remote fails or times out | External nc -zv host 25 vs local |
| Port conflict (sendmail, Dovecot, Exim) | Another process holds port 25 or 587 | ss -tlnp | grep -E ':(25|587) ' |
Quick checks
# Check master process liveness via PID file
cat /var/spool/postfix/pid/master.pid && ps -p $(cat /var/spool/postfix/pid/master.pid) -o pid,comm,start_time
# Check if Postfix thinks it is running
postfix status
# Validate configuration syntax before attempting restart
postfix check 2>&1
# Check listening sockets on SMTP ports
ss -tlnp | grep -E ':25 |:587 '
# Test the SMTP greeting locally (should return 220 with hostname)
echo QUIT | nc -w 5 localhost 25 | head -1
# Test submission port locally
echo QUIT | nc -w 5 localhost 587 | head -1
# Check inet_interfaces and inet_protocols configuration
postconf -h inet_interfaces
postconf -h inet_protocols
# Check master.cf service definitions
postconf -M smtp/inet
postconf -M submission/inet
# Count active smtpd processes (compare against maxproc)
ps aux | grep smtpd | grep -v grep | wc -l
# Look for maxproc exhaustion warnings
grep 'to limit' /var/log/mail.log | tail -10
How to diagnose it
Verify the master process is alive. Check the PID file and confirm the process exists. If the PID file points to a stale or non-Postfix process, Postfix is in an inconsistent state.
cat /var/spool/postfix/pid/master.pid ps -p $(cat /var/spool/postfix/pid/master.pid) -o pid,ppid,comm,start_timeIf master is not running, check why it stopped before restarting. Look for
fatalorpanicin the mail log. Verify there is no port conflict preventing startup.On systems using systemd,
systemctl status postfixmay showactive (exited)even when the master process is not running. The actual process state is better checked viapostfix status. On RHEL-family systems, also checksystemctl status postfix@-.Check whether any socket exists on the target port. This distinguishes “nothing listening” from “listening but not responding.”
ss -tlnp | grep -E ':25 |:587 'If no socket appears, the issue is in Postfix startup or binding. If a socket appears but belongs to a different process (sendmail, Dovecot, Exim), you have a port conflict.
If no socket exists, check inet_interfaces and inet_protocols. The upstream default for
inet_interfacesisall, but Debian and Ubuntu packages ship withinet_interfaces = localhostorloopback-only. If your host needs to receive mail from external clients, this must beall.postconf -h inet_interfaces postconf -h inet_protocolsIf
inet_protocols = allbut IPv6 is disabled on the host, Postfix may fail to bind with “cannot assign requested address.” Check the host’s IPv6 state:sysctl net.ipv6.conf.all.disable_ipv6If IPv6 is disabled, set
inet_protocols = ipv4and reload.If inet_interfaces and inet_protocols look correct, check master.cf for explicit IP bindings. An explicit IP in the service definition overrides
inet_interfaces. The smtp service line should start withsmtp inet, not127.0.0.1:smtp inet.postconf -M smtp/inet postconf -M submission/inetIf the socket is present but you get no 220 greeting, check smtpd process exhaustion. When all smtpd workers are consumed by slow clients (hung on DNS reverse lookups, milter timeouts, or content filter delays), new connections sit in the kernel queue but never get handled.
# Count smtpd processes ps aux | grep smtpd | grep -v grep | wc -l # Check the configured process limit postconf -h default_process_limit # Look for "to limit" warnings in logs grep 'to limit' /var/log/mail.log | tail -20The default
default_process_limitis 100. When the smtpd service maxproc in master.cf is-, it inheritsdefault_process_limit. If your smtpd count is at or near 100 with no free workers, you need either more capacity, postscreen to shed zombie traffic, or investigation into what is holding smtpd processes.If postscreen is enabled, test both paths. Postscreen answers on port 25 and passes compliant connections to smtpd internally. If postscreen is listening but the smtpd handoff fails, clients see connection drops or no greeting.
ps aux | grep postscreen | grep -v grep grep postscreen /var/log/mail.log | tail -20Test locally versus remotely to identify firewall interception. A socket that works on localhost but fails from an external host points to a firewall, cloud security group, or ISP block.
# Local test echo QUIT | nc -w 5 localhost 25 | head -1 # Remote test (run from another host) nc -zv -w 5 <mail-server-ip> 25Many cloud providers and residential ISPs block outbound port 25. This is not a Postfix issue, but it is the most common false positive for “Postfix not listening.”
Verify the 220 greeting contains the configured hostname. A malformed greeting indicates a
myhostnameor configuration problem.# Check configured hostname postconf -h myhostname # Compare against actual greeting echo QUIT | nc -w 5 localhost 25 | head -1The greeting should contain the configured
myhostname. If it does not, fixmyhostnamein main.cf and reload.
Metrics and signals to monitor
| Signal | Why it matters | Warning sign |
|---|---|---|
| Master process liveness | No master means no mail at all | PID file missing or points to wrong process |
| SMTP port listening | Binary availability check | Socket disappears from ss output |
| 220 greeting response time | Socket present but smtpd exhausted | Greeting takes more than 2 seconds |
| smtpd process count vs maxproc | Indicates worker pool saturation | Count at or near default_process_limit |
| “to limit” log frequency | Master cannot spawn new workers | Any occurrence for smtpd or qmgr |
| Connection establishment latency | Firewall or network degradation | External connections consistently slow or refused |
| Postscreen statistics (if enabled) | Zombie traffic overwhelming smtpd | High reject volume with concurrent smtpd saturation |
| Queue depth (active, deferred) | Backlog from smtpd unavailability | Growing deferred queue with flat delivery rate |
Fixes
Master process not running
First run postfix check to catch configuration errors that would prevent startup. Then start Postfix:
postfix start
# or
systemctl start postfix
If Postfix starts but immediately exits, check the mail log for fatal or panic messages. Common startup failures include syntax errors in main.cf or master.cf, permission problems on queue directories, and stale lock files. Remove stale PID files manually only after confirming no master process exists.
inet_interfaces bound to loopback
postconf -e 'inet_interfaces = all'
postfix reload
Note: postfix reload restarts child processes. Active connections will be interrupted.
After reloading, verify the socket is now on the external interface:
ss -tlnp | grep ':25 '
inet_protocols mismatch
If IPv6 is disabled on the host:
postconf -e 'inet_protocols = ipv4'
postfix reload
If IPv6 is enabled and you want dual-stack, leave inet_protocols = all but ensure the host actually has IPv6 connectivity. A partially configured IPv6 stack causes the same bind failure.
master.cf explicit IP binding
Edit /etc/postfix/master.cf and change the smtp service line from:
127.0.0.1:smtp inet n - y - - smtpd
to:
smtp inet n - y - - smtpd
Then reload. The explicit IP prefix overrides inet_interfaces, so removing it lets Postfix respect the inet_interfaces = all setting.
smtpd maxproc exhaustion
If smtpd processes are consistently at the limit, there are two levers:
Increase the process limit (short-term relief):
postconf -e 'default_process_limit = 200' postfix reloadThis affects all services, not just smtpd. Monitor memory and file descriptor usage after raising it. Alternatively, set maxproc only for the smtpd service in master.cf to avoid impacting other services.
Enable postscreen (structural fix). Postscreen blocks known zombie clients before they consume an smtpd process. If you have high connection volume from scanning or dictionary-attack traffic, postscreen dramatically reduces smtpd pressure.
Review the postscreen documentation for your version before enabling, as some configuration parameter names changed between Postfix releases.
Port conflict
Identify the conflicting process and either stop it or reconfigure it to listen on a different port:
ss -tlnp | grep -E ':(25|587) '
Common conflicts: Dovecot’s submission service on 587, a leftover sendmail or Exim process, or a container binding the same port.
Firewall or external block
If the socket works locally but not remotely, check in order:
- Host firewall:
iptables -L -nornft list ruleset - Cloud security group or network ACL
- ISP or upstream provider port 25 blocking (common for residential and some cloud providers)
Port 25 blocking by ISPs is an infrastructure constraint, not a Postfix problem. If you need clients to reach you on a blocked port, use port 587 (submission) for authenticated clients or route through a relay.
Prevention
- Monitor master process liveness continuously, not just via systemd unit status. Compare the PID file timestamp against the process start time to detect stale PID files after crashes.
- Alert on SMTP port unavailability externally, not just locally. An external check catches firewall and network issues that a localhost check misses.
- Track smtpd process count against maxproc. Approaching the limit is a leading indicator before connections start being refused.
- Alert on any “to limit” log message for smtpd, qmgr, or cleanup. These are info-level and easy to miss without explicit alerting.
- Review inet_interfaces and inet_protocols after every Postfix package update. Distribution updates can reset configuration to packaged defaults.
- Evaluate postscreen for any internet-facing mail server. It is the most effective way to prevent smtpd pool exhaustion from zombie traffic.
- Document the log file path for your distribution. Debian and Ubuntu use
/var/log/mail.log; RHEL-family systems use/var/log/maillog. Monitoring and manual commands must target the correct file.
How Netdata helps
Netdata collects per-second metrics and correlates listener health with mail queue state and system signals, which narrows the failure mode quickly:
- SMTP port liveness checked every second pinpoints when the socket disappears, correlating with deployments or process crashes.
- Master process monitoring detects PID file staleness and process disappearance, distinguishing a crash from a clean shutdown.
- smtpd process count tracked against
default_process_limitreveals pool saturation before connections are refused. - Log pattern detection surfaces “to limit” warnings that are otherwise buried at info level in mail logs.
- Queue depth metrics (active, deferred, incoming) correlate listener unavailability with queue growth, confirming whether smtpd exhaustion is the cause or a downstream symptom.
- Connection establishment latency from external vantage points distinguishes firewall interception from Postfix-level failures.






