The essentials

Quick reference

One focused task per row. Jump to the related section for complete, working examples.

UseSyntaxExamples
Require SCRAM for one application pathhostssl orders +orders_login 10.24.0.0/16 scram-sha-256View examples
Reject a specific source before a broad allowhost all all 10.24.9.18/32 rejectView examples
Reject non-TLS TCP connectionshostnossl all all 0.0.0.0/0 rejectView examples
Match a database named after the rolehostssl sameuser all 10.24.0.0/16 scram-sha-256View examples
Match members of a login rolehostssl orders +orders_login 10.24.0.0/16 scram-sha-256View examples
Match physical replication connectionshostssl replication replicator 10.24.40.12/32 scram-sha-256View examples
Include an ordered policy directoryinclude_dir "pg_hba.d"View examples
Include an optional local policyinclude_if_exists "pg_hba.local.conf"View examples
Locate the active HBA pathSHOW hba_file;View examples
Find parse errors in HBA filesSELECT file_name, line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;View examples
Review normalized rule orderSELECT rule_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules ORDER BY rule_number;View examples
Request a configuration reloadSELECT pg_reload_conf();View examples
Store newly set passwords as SCRAM verifiersALTER SYSTEM SET password_encryption = 'scram-sha-256'; SELECT pg_reload_conf();View examples
Reset a password without exposing it in SQL history\password orders_appView examples
Require SCRAM in the final HBA policyhostssl orders orders_app 10.24.0.0/16 scram-sha-256View examples
Require TLS, a client certificate, and SCRAMhostssl orders +orders_login 10.24.0.0/16 scram-sha-256 clientcert=verify-fullView examples
Authenticate with a client certificatehostssl orders +orders_login 10.24.0.0/16 cert map=client_certsView examples
Verify the server and require channel bindingsslmode=verify-full gssencmode=disable sslrootcert=/etc/postgresql/app-ca.crt channel_binding=require require_auth=scram-sha-256View examples
Authenticate a local socket user with peerlocal admin postgres peer map=local_adminsView examples
Map an OS account to a database rolelocal_admins db-operator postgresView examples
Use ident only on a tightly controlled networkhost admin db_operator 10.24.60.0/24 ident map=managed_hostsView examples
Use encrypted LDAP search and bindhostssl 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 GSSAPIhost all +staff 10.24.0.0/16 gss include_realm=1 krb_realm=EXAMPLE.COM map=corp_gssView examples
Require GSSAPI-encrypted transporthostgssenc all +staff 10.24.0.0/16 gss include_realm=1 krb_realm=EXAMPLE.COM map=corp_gssView examples
Scope a password-file entry tightlydb.example.com:5432:orders:orders_app:replace- WITH-managed-secretView examples
Restrict a Unix password filechmod 0600 /run/secrets/orders.pgpassView examples
Connect through a named service profilepsql service=orders-prodView examples
Verify the current authenticated sessionSELECT 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 attemptspsql '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

01

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.

Ordered application policy
# 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.

A misleading fallback that does not work
# 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.

Back to quick reference ↑
02

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.

Separate application and physical replication paths
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.

Database and role lists from managed files
# 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.

Back to quick reference ↑
03

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.

Numbered policy fragments
# 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.

Back to quick reference ↑
04

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.

Preflight the active path, errors, and order
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.

Reload only after preflight
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.

Back to quick reference ↑
05

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.

Inventory verifier types without returning verifier values
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.

Three-stage server policy
# 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.

Back to quick reference ↑
06

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.

Require both a client certificate and SCRAM
# 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.

Use the client certificate as the credential
# 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.

Back to quick reference ↑
07

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.

Mapped local administration
# 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.

Anchored realm-to-role mapping
# 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.

Back to quick reference ↑
08

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.

LDAP search and bind over encrypted hops
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.

Realm-aware GSSAPI authentication and encryption
# 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.

Back to quick reference ↑
09

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.

Split policy from the password
# ~/.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.

Connect without putting a password in the command line
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.

Back to quick reference ↑
10

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.

Production rollout and recovery checklist
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.

Verify the retained session before changing policy
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.

Back to quick reference ↑

Sources and further reading

References

Authoritative documentation used to verify and expand this cheat sheet.

  1. PostgreSQL Global Development GroupPostgreSQL 18: The pg_hba.conf Filepostgresql.org
  2. PostgreSQL Global Development GroupPostgreSQL 18: User Name Mapspostgresql.org
  3. PostgreSQL Global Development GroupPostgreSQL 18: Password Authenticationpostgresql.org
  4. PostgreSQL Global Development GroupPostgreSQL 18: ALTER SYSTEMpostgresql.org
  5. PostgreSQL Global Development GroupPostgreSQL 18: GSSAPI Authenticationpostgresql.org
  6. PostgreSQL Global Development GroupPostgreSQL 18: Peer Authenticationpostgresql.org
  7. PostgreSQL Global Development GroupPostgreSQL 18: Ident Authenticationpostgresql.org
  8. PostgreSQL Global Development GroupPostgreSQL 18: LDAP Authenticationpostgresql.org
  9. PostgreSQL Global Development GroupPostgreSQL 18: Certificate Authenticationpostgresql.org
  10. PostgreSQL Global Development GroupPostgreSQL 18: Secure TCP/IP Connections with SSLpostgresql.org
  11. PostgreSQL Global Development GroupPostgreSQL 18: Database Connection Control Functionspostgresql.org
  12. PostgreSQL Global Development GroupPostgreSQL 18: The Password Filepostgresql.org
  13. 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.

Share feedback