现象
应用连接数据库时报 FATAL: no pg_hba.conf entry for host "10.20.0.5", user "app", database "app", no encryption;本地 psql 正常,但从 Pod、CI Runner 或新网段连接就失败;故障切换或网络迁移后突然出现;使用 TLS 时报错结尾变成 SSL encryption。这说明服务端在密码校验之前就拒绝了连接,不是密码错误。
诊断
先让服务端告诉你实际读取的文件和解析结果:
SHOW hba_file;
SELECT line_number, type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules ORDER BY line_number;
如果客户端地址不在任何 address 列中,说明规则根本不匹配;error 非空则表示该行语法有误。再用 SELECT inet_client_addr(); 确认客户端源地址,检查它是否落在某个 CIDR 内,而不是只写了单个 /32。SELECT pg_conf_load_time(); 若仍等于启动时间,说明文件改了但从未重载。注意 hostssl 只接受 TLS 连接,客户端用 sslmode=disable 时同样会得到这个错误。
修复
为真实网段、用户和库补一条最精确的规则,需要强制加密时使用 hostssl:
# TYPE DATABASE USER ADDRESS METHOD
hostssl app app 10.20.0.0/24 scram-sha-256
然后执行 SELECT pg_reload_conf(); 重载,不要重启数据库。若前面有 PgBouncer,还要同步更新其 auth_file 与数据库列表。
验证
从原先失败的主机重新连接,并确认实际使用的传输方式:
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();"
返回的行应显示预期源地址且 ssl 为 t。如果仍失败,确认修改的是 SHOW hba_file 指向的实例上的文件,并排除连接池先行终止认证的可能。不要把 0.0.0.0/0 trust 当作临时方案,那等于向所有可达主机开放数据库。