pg_hba.conf: Who Can Connect
Read host-based authentication rules, add a new rule, upgrade an authentication method, and apply both with a zero-downtime reload
Every connection attempt to PostgreSQL goes through pg_hba.conf — the Host-Based Authentication file. Before a password is even checked, PostgreSQL evaluates each rule in order until one matches. That matching rule determines the authentication method. If no rule matches, the connection is rejected.\n\nA rule has five fields: connection type (local socket vs host vs hostssl), database, user, client address/CIDR, and authentication method. The most common methods are:\n\n trust — accept without any credentials (dangerous on network-accessible ports)\n md5 — password hashed with MD5 (legacy; avoid for new deployments)\n scram-sha-256 — modern password authentication (preferred)\n reject — deny the connection regardless of credentials\n\nMisunderstanding the first-match-wins rule is the most common source of access control bugs.
The pg_hba.conf Rule Format
Each line has five fields:
type database user address method
------ -------- ------- --------------- ---------------
local all postgres trust
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256
host mydb analyst 10.0.1.0/24 scram-sha-256
host all all 0.0.0.0/0 reject
Querying the Active Rules from SQL
SELECT line_number, type, database, user_name, address, auth_method
FROM pg_hba_file_rules
ORDER BY line_number;
Authentication Methods
| Method | Description | Use when |
|--------|-------------|----------|
| trust | Accept with no credentials | Local socket, dev only |
| scram-sha-256 | Modern password hash | All new deployments |
| md5 | Legacy password hash | Legacy clients only |
| reject | Always deny | Explicit block |
| peer | Match OS username | Local Unix socket |
| cert | TLS client certificate | High-security |
First-Match-Wins — The Critical Rule
-- This allows all connections from the app server:
host all all 10.0.1.50/32 scram-sha-256
-- This line NEVER fires for 10.0.1.50 because the rule above matches first:
host all all 10.0.1.50/32 reject
To block before allowing, put the reject rule first.
Adding and Hardening Rules
Editing pg_hba.conf is a two-step process: change the file, then reload — never restart. On this cluster the student account cannot write to PGDATA directly, so edits go through the as-postgres helper, which runs a command as the postgres OS user (the same helper used to read files in Lab 2.1.1).
# Add a new rule for a specific user / host / database
echo "host appdb dev_user 192.168.1.0/24 scram-sha-256" \
| as-postgres tee -a /var/lib/postgresql/18/data/pg_hba.conf
# Harden an existing trust rule bound to 127.0.0.1 to scram-sha-256 —
# match by content, not by line number, since line numbers shift as the file changes
as-postgres sed -i '/^host.*127.0.0.1.*trust$/s/trust$/scram-sha-256/' /var/lib/postgresql/18/data/pg_hba.conf
-- Apply the edits — pg_hba.conf is always sighup-context
SELECT pg_reload_conf();
-- Verify the new or changed rule from SQL
SELECT line_number, type, database, user_name, address, auth_method
FROM pg_hba_file_rules
WHERE 'dev_user' = ANY(user_name);
A reload only changes how the next connection attempt is evaluated. Sessions that already authenticated before the reload are untouched — check pg_stat_activity and you will see their backend_start timestamps predate the change, proof that nothing was disrupted.
Host-Based Authentication (HBA)
The mechanism PostgreSQL uses to decide whether a connection is permitted and how the client must authenticate. Rules are stored in pg_hba.conf and matched against each incoming connection's type, target database, username, and client address. The first matching rule determines the outcome — subsequent rules are ignored. If no rule matches, the connection is rejected.
scram-sha-256
The recommended authentication method for password-based access in PostgreSQL 10+. It performs a challenge-response exchange so the password is never sent in plaintext. It replaced MD5 as the preferred method because MD5 hashes can be cracked with modern hardware and the MD5 protocol sends the hash over the wire, enabling replay attacks.
🔌 Connect as postgres
Connect to the postgres database as the postgres superuser.
psql -U postgrespsql (18.4) Type "help" for help. postgres=#
📋 Read the HBA File Path
Use SHOW hba_file to find where pg_hba.conf lives on disk. This is useful when you need to edit it directly.
SHOW hba_file;hba_file ---------------------------- /var/lib/postgresql/18/data/pg_hba.conf (1 row)
🔍 Query pg_hba_file_rules
Query pg_hba_file_rules to see all active authentication rules. This is the live, parsed view of pg_hba.conf — no need to cat the file.
SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules ORDER BY line_number;line_number | type | database | user_name | address | auth_method -------------+-------+---------------+-----------+-----------+------------- 117 | local | {all} | {all} | | trust 119 | host | {all} | {all} | 127.0.0.1 | trust 121 | host | {all} | {all} | ::1 | trust 124 | local | {replication} | {all} | | trust 125 | host | {replication} | {all} | 127.0.0.1 | trust 126 | host | {replication} | {all} | ::1 | trust (6 rows)
🚫 Identify a reject Rule
Write a query that filters pg_hba_file_rules to show only rules that would explicitly block connections — those where auth_method = 'reject'.
SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules WHERE auth_method = 'reject';line_number | type | database | user_name | address | auth_method -------------+------+----------+-----------+---------+------------- (0 rows)
🔑 Check Authentication Method for Local Connections
Query pg_hba_file_rules to find all rules that apply to local Unix socket connections (type = 'local'). Local connections typically use trust or peer for the postgres superuser.
SELECT line_number, database, user_name, auth_method FROM pg_hba_file_rules WHERE type = 'local' ORDER BY line_number;line_number | database | user_name | auth_method -------------+---------------+-----------+------------- 117 | {all} | {all} | trust 124 | {replication} | {all} | trust (2 rows)
🕵️ Audit for Legacy md5 Rules
Audit the file for outdated authentication methods. Query pg_hba_file_rules for any rule still using md5 — a method that predates scram-sha-256 and is weaker against offline password cracking.
SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules WHERE auth_method = 'md5';line_number | type | database | user_name | address | auth_method -------------+------+----------+-----------+---------+------------- (0 rows)
🔐 Harden a Network trust Rule to scram-sha-256
Line 119 grants trust to any user, on any database, connecting over TCP to 127.0.0.1 — no password required. Edit pg_hba.conf to change that rule's method to scram-sha-256, then reload to apply it without restarting the server. Target it by matching the line's content, not its line number — line numbers shift as a file changes, so a hardcoded '119s/.../' would silently edit the wrong line if anything above it were ever added or removed. The student account cannot write to PGDATA directly, so use the as-postgres helper. It uses passwordless sudo in this lab, so no Linux password is needed; PostgreSQL password authentication is configured separately.
\! as-postgres sed -i '/^host.*127\.0\.0\.1.*trust$/s/trust$/scram-sha-256/' /var/lib/postgresql/18/data/pg_hba.confSELECT pg_reload_conf();\! PGPASSWORD= PGCONNECT_TIMEOUT=3 psql -w -h 127.0.0.1 -U student -d postgres -c "SELECT 1;"pg_reload_conf: t; psql: error: fe_sendauth: no password supplied (expected after hardening)
➕ Add a New Rule for dev_user
A developer needs access to appdb from the office network, 192.168.1.0/24. Append a new rule granting dev_user that access using scram-sha-256.
\! echo "host appdb dev_user 192.168.1.0/24 scram-sha-256" | as-postgres tee -a /var/lib/postgresql/18/data/pg_hba.confhost appdb dev_user 192.168.1.0/24 scram-sha-256
🔄 Reload Without Restarting
Apply the new rule with SELECT pg_reload_conf(). pg_hba.conf changes only ever need a reload — never a restart.
SELECT pg_reload_conf();pg_reload_conf ---------------- t (1 row)
✅ Verify the New Rule Is Live
Confirm the dev_user rule appears in the live, parsed rule set returned by pg_hba_file_rules.
SELECT line_number, type, database, user_name, address, auth_method FROM pg_hba_file_rules WHERE 'dev_user' = ANY(user_name);line_number | type | database | user_name | address | auth_method -------------+------+----------+------------+-------------+--------------- 127 | host | {appdb} | {dev_user} | 192.168.1.0 | scram-sha-256 (1 row)
👥 Confirm Existing Sessions Were Unaffected
Check pg_stat_activity for connections that were already established before the reload. A reload only changes how future connection attempts are evaluated — it never touches backends that are already running.
SELECT pid, usename, state, backend_start FROM pg_stat_activity WHERE pid <> pg_backend_pid();pid | usename | state | backend_start -----+----------+-------+------------------------------- 92 | | | 2026-06-26 16:02:25.180683+00 93 | postgres | | 2026-06-26 16:02:25.181538+00 88 | | | 2026-06-26 16:02:25.108964+00 91 | | | 2026-06-26 16:02:25.175418+00 89 | | | 2026-06-26 16:02:25.111631+00 (5 rows)
Lab 2.1.3 complete. You can now read, change, and apply authentication rules:\n\n\n SHOW hba_file : ✅ locate pg_hba.conf on disk\n pg_hba_file_rules : ✅ query live parsed rules\n First-match-wins : ✅ rule ordering understood\n trust → scram-sha-256 : ✅ network rule hardened\n New rule added : ✅ dev_user granted access\n pg_reload_conf() : ✅ applied with zero downtime\n Existing sessions : ✅ confirmed unaffected\n
Enable JavaScript to run the live terminal and track your progress.