The essentials
Quick reference
One focused task per row. Jump to the related section for complete, working examples.
| Use | Syntax | Examples |
|---|---|---|
| Require SCRAM for one application path | hostssl orders +orders_login 10.24.0.0/16 scram-sha-256 | View examples |
| Reject a specific source before a broad allow | host all all 10.24.9.18/32 reject | View examples |
| Reject non-TLS TCP connections | hostnossl all all 0.0.0.0/0 reject | View examples |
| Match a database named after the role | hostssl sameuser all 10.24.0.0/16 scram-sha-256 | View examples |
| Match members of a login role | hostssl orders +orders_login 10.24.0.0/16 scram-sha-256 | View examples |
| Match physical replication connections | hostssl replication replicator 10.24.40.12/32 scram-sha-256 | View examples |
| Include an ordered policy directory | include_dir "pg_hba.d" | View examples |
| Include an optional local policy | include_if_exists "pg_hba.local.conf" | View examples |
| Locate the active HBA path | SHOW hba_file; | View examples |
| Find parse errors in HBA files | SELECT file_name, line_number, error
FROM pg_hba_file_rules
WHERE error IS NOT NULL; | View examples |
| Review normalized rule order | SELECT rule_number,
type,
database,
user_name,
address,
auth_method
FROM pg_hba_file_rules
ORDER BY rule_number; | View examples |
| Request a configuration reload | SELECT pg_reload_conf(); | View examples |
| Store newly set passwords as SCRAM verifiers | ALTER SYSTEM
SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf(); | View examples |
| Reset a password without exposing it in SQL history | \password orders_app | View examples |
| Require SCRAM in the final HBA policy | hostssl orders orders_app 10.24.0.0/16 scram-sha-256 | View examples |
| Require TLS, a client certificate, and SCRAM | hostssl orders +orders_login 10.24.0.0/16 scram-sha-256 clientcert=verify-full | View examples |
| Authenticate with a client certificate | hostssl orders +orders_login 10.24.0.0/16 cert map=client_certs | View examples |
| Verify the server and require channel binding | sslmode=verify-full gssencmode=disable sslrootcert=/etc/postgresql/app-ca.crt channel_binding=require require_auth=scram-sha-256 | View examples |
| Authenticate a local socket user with peer | local admin postgres peer map=local_admins | View examples |
| Map an OS account to a database role | local_admins db-operator postgres | View examples |
| Use ident only on a tightly controlled network | host admin db_operator 10.24.60.0/24 ident map=managed_hosts | View examples |
| Use encrypted LDAP search and bind | hostssl all +directory_login 10.24.0.0/16 ldap ldapserver=ldap.example.com ldaptls=1 ldapbasedn="dc=example,dc=com" | View examples |
| Authenticate a Kerberos principal with GSSAPI | host all +staff 10.24.0.0/16 gss include_realm=1 krb_realm=EXAMPLE.COM map=corp_gss | View examples |
| Require GSSAPI-encrypted transport | hostgssenc all +staff 10.24.0.0/16 gss include_realm=1 krb_realm=EXAMPLE.COM map=corp_gss | View examples |
| Scope a password-file entry tightly | db.example.com:5432:orders:orders_app:replace-
WITH-managed-secret | View examples |
| Restrict a Unix password file | chmod 0600 /run/secrets/orders.pgpass | View examples |
| Connect through a named service profile | psql service=orders-prod | View examples |
| Verify the current authenticated session | SELECT current_user,
current_database(),
inet_client_addr(),
ssl
FROM pg_stat_ssl
JOIN pg_stat_activity
USING (pid)
WHERE pid = pg_backend_pid(); | View examples |
| Label canary connection attempts | psql 'service=orders-canary application_name=hba-rollout-canary' | View examples |
PostgreSQL authentication is an ordered policy evaluated at connection time. The first pg_hba.conf record matching the transport, requested database, requested role, and client address selects one authentication method; a failed attempt never falls through to a later rule. Safe production changes therefore combine narrow match criteria, authenticated encryption, client-side downgrade protection, on-disk rule inspection, a retained recovery path, and staged tests from the real client network.
Step by step
Detailed examples
Design for first match, not fallback
PostgreSQL scans HBA records from top to bottom and uses the first record whose connection type, requested database, requested user, and client address all match. If authentication under that record fails, evaluation stops: a later rule is never a backup method. Put exceptions and the narrowest trusted paths first, broader network rules later, and explicit rejects where they make policy intent reviewable. A host record matches encrypted and unencrypted TCP, so use hostssl for TLS-only access and consider hostnossl rejects for clear policy boundaries. HBA changes affect only new connections; already-authenticated sessions are not rechecked.
# pg_hba.conf: first matching record wins
host all all 10.24.9.18/32 reject
hostnossl all all 0.0.0.0/0 reject
hostssl orders +orders_login 10.24.0.0/16 scram-sha-256
hostssl metrics +reporting_login 10.24.0.0/16 scram-sha-256
host all all 0.0.0.0/0 reject
host all all ::0/0 reject Note: The address exception must precede the /16 allow. IPv4 and IPv6 are matched separately, so make the intended disposition explicit for both families.
# Do not expect the second line to run after a bad SCRAM password.
hostssl orders orders_app 10.24.0.0/16 scram-sha-256
hostssl orders orders_app 10.24.0.0/16 cert map=client_certs Note: Both records have the same match fields. The first one always selects SCRAM, and an authentication failure ends the attempt.
Constrain every matching dimension deliberately
A TCP record can restrict database, role, and source address together. In the database field, all is universal, sameuser matches a database named for the requested role, samerole requires the user to belong to the role named like the requested database, and replication matches physical replication connections. In the user field, +role matches direct or indirect members of that role, while an unprefixed name matches only that role. CIDR addresses are predictable and auditable; samehost and samenet depend on server interfaces, and host names require reverse then forward DNS agreement. Logical replication names a real database, unlike physical replication. Quoting a special keyword makes it literal rather than special.
hostssl orders +orders_login 10.24.0.0/16 scram-sha-256
hostssl sameuser analysts 10.24.20.0/24 scram-sha-256
hostssl replication replicator 10.24.40.12/32 scram-sha-256 Note: Grant role membership independently with SQL; an HBA match authenticates identity but does not grant object privileges.
# Names in these files are separated by commas or whitespace.
hostssl @app-databases +app_login 10.24.0.0/16 scram-sha-256
# app-databases
orders
billing Note: An @ file in a database or user field supplies names, while an include directive inserts complete HBA records. Keep the two mechanisms distinct during review.
Make include order visible and deterministic
include, include_if_exists, and include_dir insert records exactly where the directive appears, so the included rules participate in the same first-match sequence. include_dir processes visible files ending in .conf using C-locale filename order: numeric names sort before letters, then uppercase before lowercase. Numeric prefixes make intent obvious during review. Relative paths resolve from the directory containing the referring file. Use include_if_exists only when absence is truly optional; PostgreSQL logs a missing optional file, which should still be monitored.
# pg_hba.conf
include "pg_hba.break-glass.conf"
include_dir "pg_hba.allow.d"
include_if_exists "pg_hba.local.conf"
include "pg_hba.default-deny.conf"
# Suggested pg_hba.allow.d order:
# 10-local.conf
# 20-applications.conf
# 30-replication.conf Note: Keep directly included files outside the included directory, and place the final deny after every intentional allow and optional override.
Inspect the files on disk before requesting a reload
pg_hba_file_rules parses the current file contents and exposes source file, line number, normalized match fields, rule order, options, and errors. It is normally restricted to superusers. Crucially, it describes what is now on disk, not the rules last accepted by the server. Resolve every non-null error, review the complete order, and retain an authenticated administrator session before reloading. pg_reload_conf() requests a SIGHUP reload and its true result means the signal was sent, not that every policy behaves as intended. HBA and pg_ident changes need a reload rather than a restart on Unix-like systems; on Windows, new HBA edits apply to subsequent connections immediately. Always test with a new connection.
SHOW hba_file;
SELECT file_name, line_number, error
FROM pg_hba_file_rules
WHERE error IS NOT NULL
ORDER BY file_name, line_number;
SELECT rule_number, file_name, line_number, type, database,
user_name, address, auth_method, options
FROM pg_hba_file_rules
ORDER BY rule_number NULLS LAST, file_name, line_number; Note: An empty error query is necessary but not sufficient: syntactically valid rules can still be overly broad, shadowed, or ordered incorrectly.
SELECT pg_reload_conf() AS reload_signal_sent; Note: Confirm server logs, then exercise both expected-success and expected-denial cases through new connections from representative networks.
Migrate to SCRAM without a flag-day outage
password_encryption controls the verifier produced when a password is next set; changing it does not convert existing MD5 verifiers. First inventory client-library SCRAM support, set password_encryption to scram-sha-256, reload if the cluster default was changed through ALTER SYSTEM or a configuration file, verify the effective setting, and rotate each login role's password through a secret-safe workflow. During the compatibility stage, an HBA method of md5 automatically negotiates SCRAM when the selected role already has a SCRAM verifier, while roles with MD5 verifiers continue to use MD5. After all required clients and verifiers have migrated, change HBA records to scram-sha-256. MD5 password support is deprecated in PostgreSQL 18. Access to pg_authid is privileged and its verifier values are sensitive; classify states without selecting the hashes themselves.
SELECT CASE
WHEN rolpassword IS NULL THEN 'no-password'
WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'scram-sha-256'
WHEN rolpassword LIKE 'md5%' THEN 'md5'
ELSE 'other'
END AS verifier_type,
count(*) AS login_roles
FROM pg_authid
WHERE rolcanlogin
GROUP BY verifier_type
ORDER BY verifier_type; Note: Run this only through an appropriately privileged administrative path. Do not export pg_authid.
# Stage 1: verify every client library supports SCRAM.
# Set this in postgresql.conf/ALTER SYSTEM, reload, then verify with SHOW.
password_encryption = 'scram-sha-256'
# Stage 2: rotate passwords; keep this compatibility rule temporarily.
hostssl orders orders_app 10.24.0.0/16 md5
# Stage 3: after verifier inventory and canary tests are clean.
hostssl orders orders_app 10.24.0.0/16 scram-sha-256 Note: The compatibility behavior belongs to the md5 HBA method, not to an MD5 verifier: a SCRAM verifier triggers SCRAM automatically under that temporary rule.
Separate transport security, server identity, and client identity
hostssl only matches TLS connections and requires server-side SSL configuration, but the client must still verify whom it reached. For security-sensitive libpq clients, sslmode=verify-full validates both the CA chain and the requested host name. libpq prefers GSSAPI encryption over SSL when both are available regardless of sslmode, so set gssencmode=disable when a profile must use this TLS, client-certificate, and channel-binding path. With SCRAM over TLS, channel_binding=require requests SCRAM-SHA-256-PLUS and binds authentication to the server certificate; require_auth=scram-sha-256 additionally refuses a different server-selected authentication method. On the server, clientcert=verify-ca requires a trusted client chain, while verify-full also matches the certificate identity to the requested role or a map. The cert authentication method uses the client certificate itself and sends no password challenge. Certificate private keys, CA scope, revocation, expiry, and role mappings need their own lifecycle controls.
# Server: pg_hba.conf
hostssl orders +orders_login 10.24.0.0/16 scram-sha-256 clientcert=verify-full
# Client: pg_service.conf
[orders-prod]
host=db.example.com
port=5432
dbname=orders
user=orders_app
sslmode=verify-full
gssencmode=disable
sslrootcert=/etc/postgresql/app-ca.crt
sslcert=/run/secrets/orders-app.crt
sslkey=/run/secrets/orders-app.key
channel_binding=require
require_auth=scram-sha-256
passfile=/run/secrets/orders.pgpass Note: Use the DNS name covered by the server certificate. A bare hostaddr cannot provide the host name needed by verify-full.
# pg_hba.conf
hostssl orders +orders_login 10.24.0.0/16 cert map=client_certs
# pg_ident.conf
client_certs orders-app.prod.example.com orders_app Note: cert already performs full client-certificate validation, so adding clientcert is redundant. Keep mappings exact and anchored when regular expressions are unavoidable.
Use peer locally; treat ident as trust in the client host
peer obtains the operating-system identity from the local kernel and is available only for local socket connections on supported systems. It is a strong fit for tightly controlled administration and service accounts when pg_ident.conf explicitly maps OS identities to requested database roles. ident asks a remote client host's service which OS user owns a TCP connection; because a compromised or untrusted client can lie, it is appropriate only for closed, centrally controlled networks. Specifying ident on a local record uses peer instead. Identity maps express allowed pairs rather than permanent equivalence and are reloadable; anchor regex mappings and avoid an all target that turns one external identity into every database role.
# pg_hba.conf
local admin postgres peer map=local_admins
# pg_ident.conf
local_admins db-operator postgres Note: Protect the db-operator OS account and the local socket directory. Database authorization still follows the privileges of postgres after login.
# pg_ident.conf
corp_gss /^(orders_app)@EXAMPLE\.COM$ \1 Note: PostgreSQL regular expressions can match substrings by default. Anchors prevent an unexpected principal from matching only part of the pattern.
Integrate enterprise identity without weakening the database boundary
LDAP authentication validates a supplied username and password against the directory; the PostgreSQL role must already exist, and database privileges remain local. Prefer search+bind for flexible directory layouts, encrypt the PostgreSQL-to-LDAP hop with StartTLS or LDAPS, and independently require encryption from client to PostgreSQL. Avoid placing ldapbindpasswd in broadly readable configuration. GSSAPI provides single sign-on and can also encrypt transport. Preserve the Kerberos realm with include_realm=1, constrain krb_realm, and use an explicit pg_ident map; stripping realms is discouraged because equal names from different realms become indistinguishable. hostgssenc requires GSS-encrypted transport, while a plain host record does not.
hostssl all +directory_login 10.24.0.0/16 ldap ldapserver=ldap.example.com ldaptls=1 ldapbasedn="ou=people,dc=example,dc=com" ldapsearchattribute=uid Note: ldaptls=1 protects the server-to-directory connection. hostssl separately protects the client-to-PostgreSQL connection.
# pg_hba.conf
hostgssenc all +staff 10.24.0.0/16 gss include_realm=1 krb_realm=EXAMPLE.COM map=corp_gss
# pg_ident.conf: maintain an explicit principal allowlist
corp_gss analyst@EXAMPLE.COM analyst
corp_gss operator@EXAMPLE.COM operator Note: Use a dedicated server keytab readable by the PostgreSQL service account and test the fully qualified service host name used by clients.
Keep credentials out of URIs, arguments, logs, and source control
Although libpq accepts passwords in connection URIs, those URIs are routinely copied into shell history, process arguments, exception messages, telemetry, and deployment manifests. Keep passwords out of URIs and keyword strings. A password file stores host:port:database:user:password records and uses the first match, so place specific entries before wildcards. On Unix, group or world access makes libpq ignore the file; enforce mode 0600. A pg_service.conf profile can hold non-secret connection policy such as verify-full, channel binding, require_auth, and a passfile path. Prefer a runtime secret mount or managed credential broker, scope file access to the application identity, and rotate without changing application code. PGPASSWORD is also discouraged because some systems expose process environments.
# ~/.pg_service.conf: non-secret policy
[orders-prod]
host=db.example.com
port=5432
dbname=orders
user=orders_app
sslmode=verify-full
gssencmode=disable
sslrootcert=/etc/postgresql/app-ca.crt
channel_binding=require
require_auth=scram-sha-256
passfile=/run/secrets/orders.pgpass
# /run/secrets/orders.pgpass: mode 0600 on Unix
db.example.com:5432:orders:orders_app:replace-with-managed-secret Note: Do not commit either a real passfile or a service file that contains a password. Secret scanners and log redaction remain defense in depth.
psql service=orders-prod Note: The service profile selects the protected passfile. Ensure the service definition itself cannot redirect the application to an untrusted server.
Roll out with canaries, negative tests, and a rehearsed recovery path
Treat an HBA edit like a firewall change. Record the current paths and file versions, retain a known-good authenticated administrator session, preflight on-disk rules, and add a narrow canary rule before replacing a broad production rule. Test from the actual source network with the exact database, role, DNS name, certificate chain, and client library. Verify expected denial cases as well as success, because an unintended earlier rule can produce a successful but weaker connection. Observe server authentication logs without logging secrets, then expand gradually. A local peer-based break-glass route can be appropriate when console access and the OS account are tightly controlled. Recovery means restoring the reviewed previous files and reloading through the retained session or console—not adding trust to regain access.
1. Preserve reviewed copies of pg_hba.conf, included files, and pg_ident.conf.
2. Keep one known-good administrator session open; verify its database, role, source, and TLS state.
3. Add the narrow canary rule above the rule it will replace.
4. Query pg_hba_file_rules; resolve every error and review the complete order.
5. Reload, inspect server logs, and open a new canary connection from the real client network.
6. Test wrong role, wrong database, wrong source, missing TLS, and invalid credential cases.
7. Expand in measured stages while watching authentication failures and connection pools.
8. Remove compatibility rules only after every client path is proven.
9. If validation fails, restore the reviewed files and reload from the retained session or console. Note: Connection pools can hide policy mistakes by reusing old sessions. Force new physical connections during every test stage.
SELECT a.usename, a.datname, a.client_addr, s.ssl, s.version, s.cipher
FROM pg_stat_activity AS a
LEFT JOIN pg_stat_ssl AS s USING (pid)
WHERE a.pid = pg_backend_pid(); Note: A null client_addr commonly indicates a local Unix-domain socket. Capture the result in the change record without recording credentials.
Sources and further reading
References
Authoritative documentation used to verify and expand this cheat sheet.
- PostgreSQL Global Development GroupPostgreSQL 18: The pg_hba.conf Filepostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: User Name Mapspostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Password Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: ALTER SYSTEMpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: GSSAPI Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Peer Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Ident Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: LDAP Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Certificate Authenticationpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Secure TCP/IP Connections with SSLpostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: Database Connection Control Functionspostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: The Password Filepostgresql.org
- PostgreSQL Global Development GroupPostgreSQL 18: pg_hba_file_rulespostgresql.org
Help us improve
Found a typo or missing example?
Tell us what would make this cheat sheet clearer, more complete, or more useful.



