5.3 Client Authentication & pg_hba.conf Architecture
Key Takeaways
- Client authentication is strictly governed by the pg_hba.conf configuration file, which enforces a top-to-bottom first-matching-rule evaluation model.
- Every record in pg_hba.conf consists of mandatory fields: TYPE, DATABASE, USER, ADDRESS (for network sockets), METHOD, and optional method-specific parameters.
- Modern enterprise PostgreSQL deployments mandate scram-sha-256 for password authentication, phasing out insecure md5 hashing and plaintext trust.
- The peer authentication method applies exclusively to local Unix domain sockets, matching the client's operating system username to the PostgreSQL role via kernel socket credentials.
- Modifications to pg_hba.conf can be applied online without restarting the database server by triggering a configuration reload via pg_ctl reload or SELECT pg_reload_conf().
5.3 Client Authentication & pg_hba.conf Architecture
[!NOTE] The Meaning of HBA: In PostgreSQL, HBA stands for Host-Based Authentication. Client access is controlled by the configuration file
pg_hba.conf, situated in the cluster data directory ($PGDATA). It determines whether a client connecting from a specific network host is permitted to connect, which database and user identity they can claim, and what authentication method is enforced.
Securing access to a PostgreSQL database server begins at the connection perimeter. Long before SQL parsing, role permissions, or table ACLs are evaluated, PostgreSQL's postmaster and backend processes consult pg_hba.conf to validate incoming client connections.
The First-Matching-Rule Engine
Understanding how PostgreSQL parses pg_hba.conf is critical for avoiding catastrophic lockouts or inadvertent security holes:
Incoming Connection Request:
[Type: host | DB: app_db | User: app_user | IP: 192.168.1.50]
│
▼
+--------------------------------------------------------------------------+
| Scan pg_hba.conf Line by Line |
+--------------------------------------------------------------------------+
| Line 1: host finance_db all 192.168.1.0/24 scram-sha-256 |
| ├── Matches DB? NO (finance_db != app_db) -> Continue |
| |
| Line 2: host app_db app_user 192.168.1.50/32 reject |
| ├── Matches Type, DB, User, and IP? YES! |
| └── FIRST MATCH LOCKED IN! |
| Method is 'reject' -> CONNECTION TERMINATED IMMEDIATELY! |
| |
| Line 3: host app_db all 192.168.1.0/24 scram-sha-256 |
| └── NEVER REACHED! Line 2 already matched and decided fate. |
+--------------------------------------------------------------------------+
Core Rules of the Evaluation Engine
- Sequential Evaluation: When a client initiates a connection, PostgreSQL reads
pg_hba.conffrom top to bottom, line by line. - First Match Wins: The first record whose connection type, requested database, requested user, and client IP address match the connection parameters is selected.
- No Fall-Through: Once a record matches, PostgreSQL uses that record's designated authentication method to authenticate the client. If authentication fails under that record, the connection is aborted immediately. PostgreSQL never continues evaluating subsequent lines.
- Default Rejection: If the server reaches the end of
pg_hba.confwithout matching any record, the connection is rejected outright with a fatal error in the server log.
[!IMPORTANT] Rule Ordering Best Practice: Always place highly specific rules (individual IP addresses
/32, individual databases, specific privileged users) at the top ofpg_hba.conf, and broad catch-all rules (e.g.,0.0.0.0/0, databaseall, userall) at the bottom.
Anatomy of a pg_hba.conf Record
Each active line in pg_hba.conf consists of 4 to 7 whitespace-separated fields. A local record has no ADDRESS field, so its minimum form is only four fields (TYPE DATABASE USER METHOD); host-style records add the address and may add options:
# TYPE DATABASE USER ADDRESS METHOD [OPTIONS]
hostssl customers +app_team 192.168.1.0/24 scram-sha-256
local all postgres peer
Field 1: TYPE (Connection Mechanism)
Specifies the underlying communication protocol used by the client:
local: Matches connections made via local UNIX domain sockets (e.g.,/tmp/.s.PGSQL.5432or/var/run/postgresql/.s.PGSQL.5432). It requires no IP address in theADDRESSfield.host: Matches standard TCP/IP connections (both unencrypted plain TCP and SSL/TLS encrypted TCP).hostssl: Matches TCP/IP connections that must use SSL/TLS encryption. Plain unencrypted connection attempts matching this line are rejected immediately.hostnossl: Matches only unencrypted plain TCP/IP connections.hostgssenc/hostnogssenc: Matches TCP/IP connections using GSSAPI encryption.
Field 2: DATABASE (Target Database)
Specifies which database(s) the rule applies to:
- A specific database name (e.g.,
production,analytics). - A comma-separated list of database names (e.g.,
db1,db2,db3). all: Matches all databases on the cluster (except replication connections).sameuser: Matches if the requested database has the exact same name as the connecting user.samerole: Matches if the connecting user is a member of a role with the exact same name as the requested database.replication: Special keyword matching physical or logical replication connections (used by standbys and backup tools likepg_basebackup).@filename: Reads a list of database names from a separate external text file.
Field 3: USER (Target Role)
Specifies which PostgreSQL role(s) the rule applies to:
- A specific role name (e.g.,
postgres,app_user). - A comma-separated list of role names.
all: Matches all database roles.+group_role: Matches the specified role AND any role that is directly or indirectly a member of that group role.@filename: Reads a list of role names from an external text file.
Field 4: ADDRESS (Client Network Address)
(Present only on host, hostssl, hostnossl, hostgssenc, and hostnogssenc records):
- IPv4 with CIDR:
192.168.1.100/32(single host),10.0.0.0/16(subnet),127.0.0.1/32(IPv4 localhost),0.0.0.0/0(any IPv4 host). - IPv6 with CIDR:
::1/128(IPv6 localhost),fe80::/10(link-local),::/0(any IPv6 host). - Legacy Netmask:
192.168.1.0 255.255.255.0(specified as two separate fields). - Keywords:
all(matches any IP),samehost(matches any IP address assigned to the PostgreSQL server machine itself),samenet(matches any IP on the server's directly connected subnets).
Field 5: METHOD (Authentication Method)
Specifies how PostgreSQL verifies the client's identity. Detailed below.
Field 6: OPTIONS (Optional Configuration Parameters)
Key-value options specific to certain authentication methods (e.g., clientcert=verify-full for cert, map=admin_map for peer or ident).
Authentication Methods in Detail
| Method | Applicable Connection Types | Security Level | Operational Mechanism |
|---|---|---|---|
scram-sha-256 | host, hostssl, hostnossl, local | Highest (Modern Standard) | Salted Challenge Response Authentication Mechanism (RFC 5802/7677). Server never stores or transmits plaintext passwords. Immune to eavesdropping. |
md5 | host, hostssl, hostnossl, local | Weak / Deprecated | Legacy password hashing. Vulnerable to precomputation, packet sniffing, and hash collisions. Maintained only for legacy client compatibility. |
peer | local (UNIX sockets only) | Very High (Local Only) | Obtains the operating system username of the client process via kernel socket credentials (SO_PEERCRED). Verifies OS user matches PostgreSQL user. |
cert | hostssl only | Highest (PKI) | Validates client-side SSL/TLS certificates. Extracts the username from the certificate Subject Common Name (CN) or SAN. No password required. |
trust | local, host, hostssl | Severe Risk / Unsafe | Accepts the connection unconditionally without verifying any password or credentials. Allows anyone to claim any user identity (including postgres). |
reject | All types | Enforcement | Explicitly rejects matching connections immediately. Used to blacklist specific IP ranges or users. |
gss / sspi | host, hostssl | Enterprise Standard | Kerberos-based authentication (SSPI on Windows Active Directory). Enables enterprise Single Sign-On (SSO). |
ldap | host, hostssl | Enterprise Centralized | Forwards credentials to an external corporate LDAP or Active Directory directory service. |
pam | local, host, hostssl | Host Operating System | Delegates authentication to the Linux Pluggable Authentication Modules stack. |
Deep Dive: scram-sha-256 vs. md5 vs. trust
scram-sha-256(Default in PG 14+): PostgreSQL generates a random cryptographic salt and iteration count. Authentication involves a multi-step cryptographic handshake where neither party reveals the secret key over the wire. This is mandatory for compliance standards such as PCI-DSS and SOC 2.trust(The Danger Zone): Settinghost all all 0.0.0.0/0 trustcreates an open proxy vulnerability: any attacker across the internet can connect as superuserpostgreswithout entering any credentials.peer(Local UNIX Sockets): Standard on Linux installations (Ubuntu, Debian, RHEL). If you log into the OS shell as userpostgres, runningpsqlconnects automatically because the OS user matches the DB role. If userubunturunspsql -U postgres, connection fails with:FATAL: Peer authentication failed for user "postgres".
Reloading HBA Configuration Online
One of PostgreSQL's operational strengths is that changes to pg_hba.conf do not require restarting the database server.
How to Reload Configuration
Administrators can trigger an online reload using any of three equivalent techniques:
# Method 1: Using the pg_ctl command-line utility
pg_ctl reload -D /var/lib/pgsql/16/data
# Method 2: Using standard systemd service manager on Linux
sudo systemctl reload postgresql-16
-- Method 3: Executing SQL administrative function (Requires superuser)
SELECT pg_reload_conf();
Operational Behavior of a Reload
- The postmaster receives a
SIGHUPsignal. - It re-reads and parses
pg_hba.conf. - If a syntax error is present, PostgreSQL logs the syntax error in the server log and continues using the previously loaded, valid configuration.
- New rules take effect immediately for all subsequent incoming connections.
- Active, existing client connections are completely unaffected; they do not drop or re-authenticate.
Diagnosing Connection Rejections and the pg_hba_file_rules View
When a client cannot connect, PostgreSQL logs precise diagnostic error messages in the server log (log_directory).
Common Rejection Errors and Root Causes
-
No Matching HBA Record:
FATAL: no pg_hba.conf entry for host "192.168.1.150", user "reporting_user", database "sales_prod", no encryption- Diagnosis: No line in
pg_hba.confmatched the combination of client IP (192.168.1.150), user (reporting_user), database (sales_prod), and encryption state (unencrypted). Solution: Add an appropriatehostorhostsslrule.
- Diagnosis: No line in
-
Explicit Reject Rule Triggered:
FATAL: pg_hba.conf rejects connection for host "10.20.30.40", user "intern", database "payroll"- Diagnosis: The connection matched an explicit
rejectrule inpg_hba.conf.
- Diagnosis: The connection matched an explicit
-
Password Verification Failure:
FATAL: password authentication failed for user "app_user"- Diagnosis: A rule matched with method
scram-sha-256ormd5, but the client provided an invalid password.
- Diagnosis: A rule matched with method
-
Peer Authentication Mismatch:
FATAL: Peer authentication failed for user "postgres"- Diagnosis: Connected over local UNIX socket, but the OS username of the client process does not match the requested DB role
postgres.
- Diagnosis: Connected over local UNIX socket, but the OS username of the client process does not match the requested DB role
Inspecting Rules via SQL: pg_hba_file_rules
PostgreSQL provides the pg_hba_file_rules system view to inspect the active HBA configuration and detect syntax errors directly through SQL:
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules
WHERE error IS NOT NULL;
If error is non-null, it reveals the exact line number and syntax flaw preventing the file from parsing cleanly.
Practical Example: A Hardened Production pg_hba.conf
# =========================================================================
# Production pg_hba.conf Configuration
# =========================================================================
# 1. Local admin access via UNIX domain socket (peer authentication)
local all postgres peer
# 2. Local application access via UNIX domain socket
local all all scram-sha-256
# 3. Streaming replication standby nodes (Explicit IP addresses)
hostssl replication rep_user 10.0.10.11/32 scram-sha-256
hostssl replication rep_user 10.0.10.12/32 scram-sha-256
# 4. Explicit rejection of untrusted legacy subnet
host all all 192.168.99.0/24 reject
# 5. Production application tier (Enforce SSL + SCRAM)
hostssl prod_db +app_roles 10.0.0.0/16 scram-sha-256
# 6. IPv4 and IPv6 localhost loopback for local utilities
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
# 7. Default fallback: reject everything else
host all all all reject
Exam Tips and Common Pitfalls
- Exam Trap: Rule Order Sensitivity: The most common HBA exam question involves two conflicting rules: an explicit
rejectortrustrule followed by ascram-sha-256rule. Always remember: the first matching line decides the connection. PostgreSQL does not check subsequent lines even if the first rule rejects the user. - Exam Trap: Peer Authentication on TCP/IP:
peerauthentication works exclusively overlocalUNIX domain sockets. If an exam option suggests configuringhost all all 192.168.1.0/24 peer, that configuration is completely invalid and will trigger a syntax error on reload. - Exam Trap: Reload vs. Restart: Changing
pg_hba.confnever requires a cluster restart (pg_ctl restart). It is always applied dynamically viapg_ctl reloadorSELECT pg_reload_conf();, and active sessions are not interrupted. - Exam Trap: Group Syntax in HBA: To reference a group role and all its member users in
pg_hba.conf, the role name must be prefixed with a plus sign (+group_name). Without the plus sign, PostgreSQL treats it as a single literal username.
A PostgreSQL server has the following two lines in pg_hba.conf in this exact sequence: Line 1: host production all 10.10.5.0/24 reject Line 2: host production all 10.10.5.25/32 scram-sha-256 A user attempts to connect to database 'production' from IP address 10.10.5.25 with valid credentials. What is the result of the connection attempt?
An administrator on a Linux database host configures the following rule in pg_hba.conf: host all all 127.0.0.1/32 peer After reloading the configuration, clients attempting to connect over TCP/IP loopback fail to authenticate. Why does this rule fail to function?
An administrator modifies pg_hba.conf to grant access to a newly deployed web application server. To apply the new authentication rules immediately without interrupting hundreds of active customer database sessions, which action should the administrator perform?