Skip to content

Check listen_addresses before you change it

Severity: mediumApplies to: PostgreSQL 14+Applies to: PostgreSQL 18
The fixpostgresql.conf
Terminal window
listen_addresses = 'localhost' # the default; loopback only
# or, to serve a private network explicitly:
listen_addresses = 'localhost,10.0.0.5'

listen_addresses requires a restart, not a reload.

The default is already localhost. PostgreSQL’s own default allows only local TCP/IP loopback connections. A great deal of hardening advice tells you to set listen_addresses = 'localhost', which on a stock cluster changes nothing at all.

That makes this control unusual: the value is rarely wrong by accident. It is wrong because something changed it deliberately, and the useful question is what, not what should it be.

The two common answers:

  • The official Docker image sets listen_addresses = '*'. This is correct for a container — a database that only accepts loopback connections inside its own network namespace is useless to every other container. The exposure comes from the published port, not the setting.
  • Someone needed a remote connection. * made it work, and the change stayed long after the specific need went away.

It’s tempting to treat listen_addresses = '*' as the finding and revert it. Often that’s wrong, and it breaks things while fixing nothing.

listen_addresses decides which interfaces the server binds. It says nothing about who may connect — that is pg_hba.conf, and it is the control that actually authorises. A cluster listening on * with tight host rules and a firewall is fine. A cluster listening on localhost with host all all 0.0.0.0/0 trust is not saved by the narrow listener; it just needs one port-forward to become catastrophic.

So the order of operations is: fix the rules first, then decide about the listener. If pg_hba.conf is scoped and the port is firewalled, narrowing listen_addresses is defence in depth. If it isn’t, narrowing the listener is a fig leaf.

In containers, don’t fight the image. Leave * and control exposure at the publish and network layer — -p 127.0.0.1:5432:5432 rather than -p 5432:5432, or no published port at all when only sibling containers need it.