PostgreSQL connection refused — server not accepting connections
Connection refused — can't reach PostgreSQL server
Verified against PostgreSQL 16 documentation — Server Setup, PostgreSQL wiki — Troubleshooting connections, Linux man page — connect(2) ECONNREFUSED · Updated June 2026
> quick_fix
Connection refused means nothing is listening on the PostgreSQL port (default 5432). Either the PostgreSQL server isn't running, it's listening on a different port or interface, or a firewall is blocking the connection. Check if PostgreSQL is running with pg_isready, verify the port and listen_addresses in postgresql.conf, and check pg_hba.conf if the server is running but rejecting connections.
# Quick check if PostgreSQL is accepting connections
pg_isready -h localhost -p 5432
# If not ready, check if the service is running
systemctl status postgresql
# or on macOS:
brew services list | grep postgresql
# Start it if it's stopped
systemctl start postgresql
# or on macOS:
brew services start postgresql@16What causes this error
A connection refused error (ECONNREFUSED) occurs at the TCP level before any PostgreSQL protocol exchange happens. The operating system's TCP stack received a SYN packet on the target port and responded with RST (connection refused) because no process is listening on that port. This means: PostgreSQL is not running, it's running but listening on a different port than you're connecting to, it's listening on a different network interface (e.g., only on localhost when you're connecting from another host), or a host-level firewall (iptables, ufw, security group) is blocking the port. This is distinct from 'could not connect to server: Connection timed out' (firewall drops packets silently) and from pg_hba.conf authentication errors (connection succeeds but login fails).
How to fix it
- 01
step 1
Check if PostgreSQL is running
The most common cause: the server simply isn't running. It may have failed to start after a reboot, crashed due to disk space, or was never installed.
# Check service status systemctl status postgresql # or pg_isready -h localhost -p 5432 # Check if anything is listening on port 5432 ss -tlnp | grep 5432 # or on macOS: lsof -i :5432 # If not running, check logs for why it failed to start journalctl -u postgresql --since '1 hour ago' # or check the PostgreSQL log directory tail -50 /var/log/postgresql/postgresql-16-main.log - 02
step 2
Verify listen_addresses and port in postgresql.conf
PostgreSQL defaults to listening only on localhost. If you're connecting from another machine, it won't accept the connection even if it's running.
# Find and check postgresql.conf sudo -u postgres psql -c "SHOW config_file;" grep -E '^(listen_addresses|port)' /etc/postgresql/16/main/postgresql.conf # Default: listen_addresses = 'localhost' # To accept connections from other hosts: # listen_addresses = '*' # Then restart: systemctl restart postgresql # Verify the actual listening address after restart ss -tlnp | grep postgres # Should show 0.0.0.0:5432 (all interfaces) not 127.0.0.1:5432 (localhost only) - 03
step 3
Check firewall rules
Even if PostgreSQL is running and listening on all interfaces, a firewall may block port 5432. Check both host-level firewalls and cloud security groups.
# Check ufw (Ubuntu) sudo ufw status verbose | grep 5432 sudo ufw allow 5432/tcp # Check iptables sudo iptables -L -n | grep 5432 # AWS Security Group — check inbound rules aws ec2 describe-security-groups --group-ids sg-xxx \ --query 'SecurityGroups[].IpPermissions[?FromPort==`5432`]' # Test connectivity from client machine nc -zv db-host.example.com 5432 # or telnet db-host.example.com 5432 - 04
step 4
Check connection string parameters
If the server is running and reachable, the connection string in your application might have the wrong host, port, or socket path.
# Common connection string mistakes: # Wrong: postgresql://localhost:5433/mydb (wrong port) # Wrong: postgresql://db-server:5432/mydb (hostname not resolving) # Wrong: postgresql:///mydb?host=/tmp (wrong Unix socket path) # Verify with psql using explicit parameters psql -h localhost -p 5432 -U postgres -d mydb # Check the Unix socket directory PostgreSQL uses sudo -u postgres psql -c "SHOW unix_socket_directories;" # On macOS with Homebrew, the socket is often at: # /tmp/.s.PGSQL.5432
How to verify the fix
- pg_isready -h <your-host> -p 5432 returns 'accepting connections'.
- Your application can connect and execute a simple SELECT 1 query.
- ss -tlnp | grep 5432 shows PostgreSQL listening on the expected interface.
- Remote connections work if listen_addresses was changed to '*'.
Why ECONNREFUSED happens at the runtime level
ECONNREFUSED is a TCP-level error, not a PostgreSQL-level error. When a client sends a TCP SYN packet to port 5432 and the operating system on the target host has no process bound to that port, the kernel responds with a TCP RST (reset) packet. The client's connect() system call then fails with errno ECONNREFUSED. This happens before any PostgreSQL wire protocol exchange. The distinction matters for diagnosis: if you see ECONNREFUSED, the problem is never authentication, pg_hba.conf, SSL, or database permissions — it's that the TCP connection itself can't be established. Either the server process isn't running, it's listening on a different port/interface, or a firewall is injecting RST packets.
Common debug mistakes for ECONNREFUSED
- Editing pg_hba.conf when the error is connection refused — pg_hba.conf only matters after a TCP connection succeeds. Connection refused means the connection never established at all.
- Checking only the default port 5432 when a managed database service (RDS, Cloud SQL, Supabase) uses a custom port — check your connection string or dashboard.
- Assuming localhost means 127.0.0.1 when PostgreSQL on some systems binds to an IPv6 socket (::1) but the client connects via IPv4 — explicitly use -h 127.0.0.1 or -h ::1 to test.
- Forgetting to restart PostgreSQL after changing listen_addresses — unlike pg_hba.conf (which can be reloaded), listen_addresses changes require a full server restart.
- On macOS with Homebrew, running psql as root instead of the current user — Homebrew PostgreSQL runs as your user, not as a postgres system user.
When ECONNREFUSED signals a deeper problem
Intermittent connection refused errors (works sometimes, fails other times) usually indicate one of three issues: (1) PostgreSQL is crashing and auto-restarting — check logs for panic messages and the postmaster cycling; (2) a connection pooler like PgBouncer is between your app and PostgreSQL and it's the pooler that's going down, not PostgreSQL itself — check which process is actually bound to the port your app connects to; (3) in containerized environments, the PostgreSQL container restarts during health check failures or resource limits, and your app tries to connect during the restart window — add connection retry logic with backoff to your application's database initialization.
Editor's take
Connection refused is the simplest PostgreSQL error to diagnose but one of the most frustrating to encounter because it blocks all work. The mental model is straightforward: is anything listening on port 5432?
Run pg_isready or ss -tlnp | grep 5432. If nothing is listening, start PostgreSQL. If PostgreSQL won't start, read the log file — the last few lines always explain why (disk full, stale PID file, config syntax error). Ninety percent of connection refused cases end here.
The remaining ten percent involve network topology: you're connecting to a remote server and something between you and it is blocking port 5432. Cloud security groups are the most common culprit — AWS security groups are stateful and deny by default, so a new database instance won't accept connections until you explicitly add an inbound rule for port 5432. I've seen developers debug for an hour before checking the security group.
The docker-compose trap is worth calling out: your app container starts before the PostgreSQL container is ready. The database port is mapped, PostgreSQL is technically running, but it's still in recovery mode and not accepting connections yet. Add a depends_on with a health check, or better yet, implement connection retry logic in your application startup. Every production application should retry database connections with backoff — not just for docker-compose, but for any infrastructure restart.
By Bikram Nath · Curator · Updated June 2026
Frequently asked questions
What's the difference between connection refused and connection timed out?
Connection refused (ECONNREFUSED) means the target host actively rejected the connection — the TCP RST packet came back immediately. This means the host is reachable but nothing is listening on that port. Connection timed out means no response at all — the packets are being dropped silently, usually by a firewall or because the host is unreachable. Refused = fast failure, check if the server is running. Timed out = slow failure, check firewalls and network routing.
Why does connection work with psql but not from my application?
If psql connects but your app doesn't, check: (1) psql might be using a Unix socket (local connection) while your app uses TCP — verify the host parameter; (2) your app's connection string might have a different port; (3) pg_hba.conf might allow local connections but reject TCP connections from your app's IP. Run psql with the exact same host, port, and user your app uses to replicate the issue.
PostgreSQL won't start after a crash — what do I check?
Check the PostgreSQL log for the startup failure reason. Common causes: a stale PID file (postmaster.pid) from a previous crash — delete it and restart; disk full — PostgreSQL requires space for WAL files and won't start without it; corrupted WAL files after a hard crash — run pg_resetwal as a last resort (data loss risk); or a configuration syntax error in postgresql.conf after a recent edit.