← Debugging Guides

阅读中文版本

PostgreSQL no pg_hba.conf entry — Fix Host-Based Authentication

Diagnose PostgreSQL FATAL: no pg_hba.conf entry errors by reading pg_hba_file_rules, matching client address and SSL mode, then adding and reloading a host rule.

beginnerdebuggingpostgresqlauthentication

Symptoms

  • FATAL: no pg_hba.conf entry for host "10.20.0.5", user "app", database "app", no encryption
  • psql works from localhost but fails from an application pod or CI runner
  • The error appears immediately after a database failover or network migration
  • Connections using TLS report the same message with SSL encryption instead of no encryption

Possible causes

  • The client subnet is missing from pg_hba.conf or is covered by a narrower rule
  • A hostssl rule exists but the client connects without TLS, or a hostnossl rule blocks it
  • The rule was edited on disk but the server was never reloaded
  • The connection lands on a different PostgreSQL instance or a pooler with its own authentication file

Diagnosis steps

Ask the server which file and line it is using

psql -U postgres -c "SHOW hba_file;" -c "SELECT line_number, type, database, user_name, address, auth_method, error FROM pg_hba_file_rules ORDER BY line_number;"

Interpretation

The view shows every parsed rule plus a non-null error column for invalid lines. If the client address appears in no address column, the rule simply does not exist.

Reproduce with the exact client address and SSL mode

psql "host=db.internal port=5432 dbname=app user=app sslmode=require" -c 'select inet_client_addr(), ssl from pg_stat_ssl where pid = pg_backend_pid();'

Interpretation

A failure before the query runs confirms authentication, not SQL, is the blocker. The message reports whether the client presented TLS.

Compare the client address with the rule coverage

psql -U postgres -c "SELECT name, setting FROM pg_settings WHERE name = 'listen_addresses';" -c "SELECT inet_client_addr();"

Interpretation

Verify the client is reaching the intended instance and that its source address falls inside a listed CIDR instead of a single host entry.

Check whether a reload actually happened

psql -U postgres -c "SELECT pg_conf_load_time(), pg_postmaster_start_time();"

Interpretation

pg_conf_load_time should be later than your edit. If it matches the startup time, the file was never reloaded.

Root cause

PostgreSQL authorizes each connection against the first matching pg_hba.conf line for its type, database, user, and source address. When no line matches, or a hostssl line requires TLS that the client did not offer, the server rejects the connection before authentication completes. Editing the file alone changes nothing until the postmaster reloads it.

Fix

Add a rule that matches the real client network, user, and database, and choose hostssl when TLS is mandatory. Reload with SELECT pg_reload_conf() rather than restarting. If a pooler such as PgBouncer sits in front, update its auth_file and database list as well. Keep rules ordered from most specific to most general and avoid broad trust entries.

Risk note

A rule such as host all all 0.0.0.0/0 trust exposes the database to every reachable host. Reloading is safe, but a malformed file can make the next connection fail, so validate with pg_hba_file_rules before disconnecting the current session.

Verify the fix

Reconnect from the failing host and confirm the session starts, then run SELECT inet_client_addr(), ssl FROM pg_stat_ssl WHERE pid = pg_backend_pid(); and check the address and TLS state match the intended rule.

The error names the rule that is missing

FATAL: no pg_hba.conf entry for host "10.20.0.5", user "app", database "app", no encryption means the postmaster found no matching line in its host-based authentication file. It is not a wrong password: the server rejected the connection before password verification.

FATAL:  no pg_hba.conf entry for host "10.20.0.5", user "app", database "app", no encryption

The trailing no encryption or SSL encryption tells you which transport the client used, which matters when the only matching rule is hostssl.

Inspect the effective rules

Query the parsed file instead of guessing. The error column exposes syntax problems and the line_number matches the file you are editing.

SHOW hba_file;
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules ORDER BY line_number;

Compare the client address reported by inet_client_addr() with the address column. A /32 entry for one pod does not cover a rolling deployment that adds new pod IPs.

Add the narrowest rule that works

# TYPE     DATABASE  USER  ADDRESS         METHOD
hostssl   app       app   10.20.0.0/24    scram-sha-256

Reload and re-check the view. A reload (SELECT pg_reload_conf();) is enough for pg_hba.conf; a restart is not required and would drop every session.

Verify from the failing host

Connect with the original connection string and confirm the negotiated transport:

psql "host=db.internal dbname=app user=app sslmode=require" \
  -c "select inet_client_addr(), ssl from pg_stat_ssl where pid = pg_backend_pid();"

If the connection still fails, confirm you edited the file returned by SHOW hba_file on the instance that actually received the connection, and that no pooler terminates authentication first.