TCP connection refused -- nothing listening on the port or explicit REJECT rule
curl: Connection refused immediately (no timeout delay)
Focused incident mode — strips away everything but this runbook.
Symptoms
- curl: Connection refused immediately (no timeout delay)
- nc -zv <host> <port> returns Connection refused
- ss -tlnp does not show the expected port in LISTEN state
Evidence to grab
Collect these artifacts before you change anything — they prove (or rule out) each cause.
Listening ports on the server
ss -tlnp | grep <PORT>Firewall REJECT rules
iptables -L -n -v | grep REJECT
Diagnostic flow
Run the steps in order, marking each claim confirmed or refuted. The evidence you gather feeds the ranked causes below.
Guided decision tree is ready.
Steps with commands, expected output, and pass/fail branches.
Ranked root causes
Evidence checklist
- ss -tlnp shows no LISTEN on the port
- systemctl status <service> shows inactive/failed
Confirm before fixing
systemctl status <service> | head -15Check the service status
Fix
systemctl start <service>Start the service
Resolution runbook
Apply from top to bottom after the cause is confirmed. Review every command before running it — risk tags are shown on each.
ss -tlnp | grep <PORT>Check if the service is listening
systemctl status <service>Check the service status
systemctl start <service>Start the service if it is down
iptables -L INPUT -n -v | grep REJECTCheck for REJECT firewall rules
Prevention
- Use process monitoring (systemd, supervisor) to auto-restart crashed services.
- Set up port monitoring (blackbox exporter) to alert when expected ports are not listening.
- Document the expected bind address (0.0.0.0 vs 127.0.0.1) for every service.
- Use firewall rule documentation and avoid blanket REJECT rules on service ports.
Related runbooks
Same stack, same failure family — worth a skim.
curl: Connection timed out after 30-120s instead of refused
bind: Address already in use error on application startup
Commands marked READ CHANGE DESTRUCTIVE — never run DESTRUCTIVE commands against production data you cannot restore. Copy → verify → execute.