pg_hba.conf & Authentication
pg_hba.conf (host-based authentication) decides which clients may connect, from which addresses, to which databases, using which auth method. It is your first network and identity firewall.
Recipe
# TYPE DATABASE USER ADDRESS METHOD
local all postgres peer
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
hostssl myapp app_user 10.0.0.0/8 scram-sha-256# Validate syntax and reload
sudo -u postgres pg_ctl reload -D /var/lib/postgresql/18/mainWhen to reach for this: Any time you open Postgres beyond localhost, add an app role, or rotate auth methods.
Working Example
# Reject by default - explicit allows only
host all all 0.0.0.0/0 reject
# App tier subnet
hostssl myapp_prod app_rw 10.10.1.0/24 scram-sha-256
hostssl myapp_prod app_ro 10.10.2.0/24 scram-sha-256
# Replication from standby subnet
host replication replicator 10.10.3.10/32 scram-sha-256
# Local admin socket
local all postgres peer-- Create login roles with passwords (stored as SCRAM verifier)
CREATE ROLE app_rw LOGIN PASSWORD 'rotate-me-via-vault';
CREATE ROLE app_ro LOGIN PASSWORD 'rotate-me-via-vault';
GRANT CONNECT ON DATABASE myapp_prod TO app_rw, app_ro;What this demonstrates:
hostsslrequires TLS - use for remote app connections- Separate roles and subnets for read-write vs read-only
rejectas catch-all after specific rules (order matters - first match wins)replicationis a pseudo-database for physical replication connections
Deep Dive
Rule Fields
| Field | Values | Meaning |
|---|---|---|
| TYPE | local, host, hostssl, hostnossl | Socket vs TCP; TLS requirement |
| DATABASE | name, all, sameuser, replication | Target database |
| USER | name, all, +group | + prefix matches group roles |
| ADDRESS | CIDR, hostname | Omit for local |
| METHOD | scram-sha-256, cert, peer, reject | How identity is verified |
Auth Methods (Production)
# Preferred for password auth (PG 10+)
password_encryption = scram-sha-256 # in postgresql.conf
# Certificate auth (mTLS)
hostssl all app_user 0.0.0.0/0 cert clientcert=verify-fullmd5is legacy - migrate toscram-sha-256.trustandpassword(cleartext) are audit failures - never on networks.peermaps OS user to DB user on Unix sockets - good for localpostgresadmin.
Least-Privilege Network Rules
- One CIDR per security zone (app, batch, BI, admin bastion).
- Narrow
DATABASEandUSER- avoidall allon wide CIDRs. - Use separate listeners:
listen_addressesonly on internal NICs when possible.
Reload Behavior
pg_hba.confchanges apply onSIGHUPreload - no restart.- Syntax errors on reload keep the old file active - test with
pg_hba_file_rulesview (PG 12+):
SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;Gotchas
- Rule order surprises - First matching line wins; a broad
host all all 0.0.0.0/0 scrambefore arejectnever reaches reject. Fix: Most specific rules first, reject last. - Forgot hostssl on public networks - Password without TLS is sniffable. Fix:
hostssl+ valid server cert, or VPN/private link only. - peer auth over TCP -
peeronly works forlocalsocket connections. Fix: Usescram-sha-256orcertforhostentries. - Replication rule missing - Standby cannot connect with app-only rules. Fix:
host replication replicator <standby-ip>/32 scram-sha-256. - IPv6 overlooked -
::1open withtrustwhile IPv4 is locked. Fix: Mirror policies for::1/128or disable IPv6 listener.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
cert client authentication | mTLS service mesh, no shared passwords | Clients cannot manage cert rotation |
| RDS security groups | Managed cloud network ACL | Self-hosted bare metal |
| SSH tunnel to localhost | Emergency admin access | Production app steady-state path |
FAQs
Where is pg_hba.conf?
SHOW hba_file; or pg_config --hbafile on some installs. Usually alongside postgresql.conf in PGDATA.
Why connection rejected with no hint?
Check server log after log_connections = on. Common causes: no matching rule, pg_hba.conf typo, or SSL required but client uses plain.
scram-sha-256 vs md5?
SCRAM stores salted verifiers and does not send reusable password hashes on the wire. Migrate roles with ALTER ROLE ... PASSWORD 'new'.
Can I use LDAP?
Yes via ldap or radius methods - common in enterprises. Still keep narrow CIDR rules.
Does reload drop connections?
No. Existing sessions keep their original auth context; new connections use the updated file.
Related
- Installation Basics - install before hardening auth
- Roles Basics - roles referenced in hba rules
- SCRAM Authentication - password storage depth
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.