Incident Response

PostgreSQL "Connection refused": Is the Server Running? How to Find Out

"Connection refused" means your client never reached PostgreSQL at all. The cause is almost always one of five things, and on a large database one of them is simply a server still replaying WAL after a crash.

· 12 min read · AG Data Team

PostgreSQL "Connection refused" is the client telling you that nothing accepted its connection on that address and port. It is not an authentication or permission error: PostgreSQL never saw your request. The good news is that the list of causes is short, and four commands are usually enough to tell which one you have.

The full message comes from libpq, so psql, most drivers and many tools print the same text. On current versions it looks like this:

$ psql -h 10.0.1.20 -U app appdb
psql: error: connection to server at "10.0.1.20", port 5432 failed: Connection refused
	Is the server running on that host and accepting TCP/IP connections?

$ psql appdb
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed: No such file or directory
	Is the server running locally and accepting connections on that socket?

The second line is a hint, not a diagnosis. The libpq source prints "Is the server running on that host and accepting TCP/IP connections?" for any TCP failure of this kind, and the socket variant for local connections. If you do reach the server and it rejects you, you get a different error, such as the ones in our pg_hba.conf entry guide.

Refused, timed out, or rejected: three different problems

Check it in four commands

# 1. does the server answer at all? (0 ok, 1 rejecting, 2 no response)
pg_isready -h 10.0.1.20 -p 5432; echo $?

# 2. on the database host: is anything listening, and where?
ss -ltnp | grep 5432
ss -lx  | grep PGSQL

# 3. is the service running, and what did it log?
systemctl status postgresql
journalctl -u postgresql --since "30 min ago"

# 4. what does the server think it should listen on?
psql -c "SHOW listen_addresses" -c "SHOW port" -c "SHOW unix_socket_directories"

pg_isready is the fastest first step: it returns 0 when the server accepts connections, 1 when it is rejecting them (for example during startup), 2 when there is no response, and 3 when no attempt was made because of bad parameters. Exit code 1 and exit code 2 lead to completely different investigations.

The usual causes

  1. PostgreSQL is not running. It crashed, was stopped, or failed to start. The service status and the server log tell you which. A full disk is a common reason it will not start, see PostgreSQL disk full: pg_wal. Other frequent ones are a typo in postgresql.conf, a stale postmaster.pid after an unclean shutdown, or a data directory that is missing because a volume did not mount.
  2. It listens only on localhost. The default listen_addresses is localhost, which allows only loopback TCP connections. Remote clients get "Connection refused" until you add the server's address or *. This parameter is only read at server start, so a reload does nothing.
  3. Wrong port. The default is 5432, but a second cluster on the same host (common on Debian and Ubuntu after an upgrade) often runs on 5433. ss -ltnp shows what is actually bound.
  4. Wrong socket directory. For local connections the client and server must agree on unix_socket_directories. The documentation says the default is normally /tmp but can be changed at build time, and Debian-family packages use /var/run/postgresql. A client built for one layout and a server built for another produce "No such file or directory" even though PostgreSQL is running. Use -h /path/to/socket/dir to point the client at the right place.
  5. A firewall in between. Host firewall, cloud security group, Kubernetes network policy. A rejecting rule looks like "refused", a dropping rule looks like a timeout.
# postgresql.conf (restart required, reload is not enough)
listen_addresses = 'localhost,10.0.1.20'   # default is 'localhost'
port = 5432
Opening listen_addresses is only half the change. Once the server listens on a public or private interface, pg_hba.conf decides who may connect. Add narrow rules for the application subnets, keep scram-sha-256, and never pair listen_addresses = '*' with a wide-open firewall.

A subtle one: the address was not there at boot

The documentation notes that if listen_addresses is not empty, the server starts as long as it can listen on at least one address, and only emits a warning for the ones it cannot open. If PostgreSQL starts before a virtual IP, a secondary interface or a cloud network attachment is ready, it may come up on localhost only and refuse every remote client, while systemctl status shows it as running. Look for that warning in the startup log, and make the service wait for the network it needs.

What changes on large databases: crash recovery takes time

On a busy multi-terabyte database, the most common reason clients cannot connect after an incident is not a configuration mistake. The server is replaying WAL. After a crash, PostgreSQL must redo everything written since the last checkpoint before it accepts connections. During that time clients see the database system is starting up, or "Connection refused" if the postmaster is not up yet, for example while a supervisor is still restarting it.

LOG:  database system was interrupted; last known up at ...
LOG:  redo starts at 3A/1C000028
LOG:  redo in progress, elapsed time: 10.01 s, current LSN: 3A/5F2D1B40
LOG:  redo in progress, elapsed time: 20.02 s, current LSN: 3A/A1E09C88
...
LOG:  database system is ready to accept connections

Key takeaways

PostgreSQL Connectivity Troubleshooting Recovery
Work with us

PostgreSQL down and not coming back?

We get production PostgreSQL back online: failed starts, long crash recovery, broken failovers and connection problems, with a clear plan so it does not happen again.

Get in touch More from the blog