正德厚生,臻于至善

PostgreSQL 连接排错与 pg_hba.conf 配置解析

环境:pgcm1(10.0.0.231:5432),以 OS 用户 postgres 登录操作
数据库版本:PostgreSQL 18.6(psql (18.6))
虚拟化平台:VMware Workstation;NAT 网段 10.0.0.0/24(VMnet8),Host-Only 网段 10.0.10.0/24(VMnet1)
整理日期:2026-11-07(含宿主机访问章节与实操排查记录)


一、故障现象

[postgres@pgcm1 data]$ psql 10.0.0.231 -p 5432 -d postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  role "10.0.0.231" does not exist

[postgres@pgcm1 data]$ psql localhost -p 5432 -d postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  role "localhost" does not exist

[postgres@pgcm1 data]$ psql 127.0.0.1 -p 5432 -d postgres
psql: error: connection to server on socket "/tmp/.s.PGSQL.5432" failed:
FATAL:  role "127.0.0.1" does not exist

三条命令全部报同一个角色不存在的错误,且都指向 Unix socket(/tmp/.s.PGSQL.5432)而不是 TCP。


二、根因分析

2.1 psql 的位置参数是 dbname,不是 host

psql 的语法是:

psql [选项] [dbname [username]]

第一个位置参数一律被当成数据库名,主机必须用 -h 显式指定。

所以 psql 10.0.0.231 -p 5432 -d postgres 的实际行为是:

  • 10.0.0.231 → 被解析为 dbname(随后又被后面的 -d postgres 覆盖/冲突)
  • 没有 -h → 客户端使用默认的 Unix domain socket
  • 该字符串被当作连接标识参与认证,于是服务端报 role "10.0.0.231" does not exist

localhost 和 127.0.0.1 完全同理,三者错误表现一致,正说明问题不在网络、不在 pg_hba,而在命令写法。

2.2 为什么报 role 而报 database

服务端认证阶段先解析角色,角色不存在即在认证层直接 FATAL 退出,还没走到数据库存在性检查。所以看到 role ... does not exist 并不代表 pg_hba 有问题。

2.3 一个判断口诀

报错内容指向的环节
role "xxx" does not exist客户端发出的用户名不对(-U 或位置参数被误用)
database "xxx" does not exist角色 OK,库名不对
no pg_hba.conf entry for host "x.x.x.x"角色/库都可能 OK,服务端没放行该来源 IP
password authentication failed认证方法或密码存储格式不匹配(见第四节的 md5/SCRAM 陷阱)
Peer authentication failed走了 socket,local 是 peer 且 OS 用户与角色名不一致
connection refusedlisten_addresses 未含该地址,或防火墙/端口不通

三、正确写法

# 走 TCP 连远端/本机业务 IP
psql -h 10.0.0.231 -p 5432 -U postgres -d postgres
psql -h 127.0.0.1  -p 5432 -U postgres -d postgres
psql -h localhost  -p 5432 -U postgres -d postgres

# 走本地 Unix socket(peer/trust 认证,OS 用户 postgres 直接匹配同名角色)
psql -d postgres

# URI 形式,一条搞定
psql "postgresql://postgres@10.0.0.231:5432/postgres"

补充要点:

  • -h 之后不带 -U 时,默认用户名仍是 OS 用户名(此处为 postgres),不是 dbname。
  • 避免交互提示密码可用 PGPASSWORD 环境变量或 ~/.pgpass(权限须为 600)。
  • 排查时加上 -v ON_ERROR_STOP=1 便于脚本化判断退出码。

四、pg_hba.conf 逐条解析

4.1 规则格式与匹配语义

连接类型  数据库  角色  来源地址              认证方法
host      all     all   10.0.0.231/32        trust

核心语义:从上往下匹配,第一条命中的规则立即生效并停止后续查找。

不存在”最精确优先”,只有”先出现优先”。这一点决定了本文后面几乎所有问题的成因。

列含义补充:

  • host 同时覆盖 IPv4 与 IPv6 的 TCP 连接;local 只覆盖 Unix domain socket。
  • 数据库列 all 不包含 replication 这个伪数据库,复制连接必须单独成行。
  • hostssl / hostnossl 用于按 SSL 与否分流,本文件未使用。

4.2 本文件实际内容逐条拆解

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
host    all             all             10.0.0.231/32           trust
host    all             all             0.0.0.0/24              trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# Allow replication connections from localhost, by a user with the
# replication privilege.
local   replication     all                                     trust
host    replication     all             127.0.0.1/32            trust
host    replication     all             ::1/128                 trust

host    all             all             0.0.0.0/0               md5
host    all             all             0.0.0.0/0               scram-sha-256
#配置行解析
1# "local" is for Unix domain socket connections only默认模板注释,说明 local 类型仅对 Unix socket 生效(/tmp/.s.PGSQL.5432、/var/run/postgresql/.s.PGSQL.5432)
2local all all trustsocket 连接、所有库、所有角色、免密。任何能访问该 socket 的 OS 用户都可自称任意角色(含 postgres 超级用户),是本机最大越权面
3host all all 127.0.0.1/32 trust仅本机 IPv4 回环,/32 为精确匹配单个 IP,免密
4host all all 10.0.0.231/32 trust仅来源 IP 恰为 10.0.0.231(本机业务 IP)的 TCP 连接,免密
5host all all 0.0.0.0/24 trust写错。0.0.0.0/24 = 0.0.0.0 ~ 0.0.0.255,属保留的无效/未指定网段,真实客户端 IP 永不落入此区间,该行永不命中(死规则)。原意应为 10.0.0.0/24
6host all all ::1/128 trustIPv6 回环 ::1 精确匹配,免密
7local replication all trustsocket 上的物理/流复制连接,免密。仅覆盖 socket,pg_basebackup -h 走 TCP 不受此行保护;角色自身还需 REPLICATION 权限或超级用户
8host replication all 127.0.0.1/32 trust回环 IPv4 上的复制连接,免密
9host replication all ::1/128 trust回环 IPv6 上的复制连接,免密
10host all all 0.0.0.0/0 md5兜底规则 1:任意 IPv4 来源,md5 方式认证。因位置靠前,实际是所有非本机 IPv4 客户端的最终归宿
11host all all 0.0.0.0/0 scram-sha-256兜底规则 2:任意 IPv4 来源用 SCRAM-SHA-256。但被第 10 行完全遮蔽,永远轮不到,属死规则

五、问题清单(按危害排序)

1)第 10、11 行互相打架,md5 屏蔽了 scram —— 最隐蔽的坑

PostgreSQL 14 起 password_encryption 默认即为 scram-sha-256,角色密码存的是 SCRAM 验证子($SCRAM-SHA-256$...)。

而 md5 认证方法无法校验 SCRAM 存储的密码。后果:远端 10.0.0.x 的客户端即使密码完全正确,也会收到 password authentication failed,且日志里看不出所以然。

处理:删除第 10 行,或把两行合并为一条 host all all 0.0.0.0/0 scram-sha-256。

2)0.0.0.0/24 是无效网段

应改为 10.0.0.0/24。本意大概是”同网段免密”,但实际等于没写;同网段其他机器会落到 md5 兜底,行为与预期不一致。

结合真实拓扑(VMware NAT 网段即 10.0.0.0/24),这一行正是宿主机访问所需要的规则,修正方式与完整步骤见第八章。

3)大面积 trust

第 2、4 行均为 all + trust:能建 socket 或能从 10.0.0.231 发起连接者,可任意指定角色名进入,包括 postgres。

生产环境建议:local 改 peer(OS 用户名须与角色名一致);host ... 10.0.0.231/32 改 scram-sha-256。

4)IPv6 客户端会被直接拒绝

0.0.0.0/0 在 pg_hba 中只匹配 IPv4,不匹配 IPv6。因此除 ::1 外的 IPv6 客户端无任何规则命中,报 no pg_hba.conf entry for host ...。不需要 IPv6 可不配,需要则补 host all all ::0/0 scram-sha-256。

5)复制规则只覆盖本机

第 7–9 行只允许回环与 socket 复制。若要加备库(另一台 10.0.0.x),pg_basebackup -h 10.0.0.231 会落到 md5 兜底,同样可能因 SCRAM 存储而失败。

6)缺少 hostssl

若要求传输加密,需显式使用 hostssl 并对 host 收紧,否则明文连接仍被放行。


六、建议改写版本

# ===== 本地 Unix socket:用 peer,比 trust 安全 =====
local   all             postgres                                peer
local   all             all                                     peer

# ===== 本机回环 =====
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             ::1/128                 scram-sha-256

# ===== 同网段:明确写 10.0.0.0/24,切勿写 0.0.0.0/24 =====
host    all             all             10.0.0.0/24             scram-sha-256
host    all             all             10.0.0.231/32           trust      # 仅内部自动化/监控

# ===== 复制:显式放行备库网段 =====
host    replication     replicator      10.0.0.0/24             scram-sha-256
local   replication     all                                     peer

# ===== 兜底:只留一条,方法统一 =====
host    all             all             0.0.0.0/0               scram-sha-256
host    all             all             ::0/0                   scram-sha-256

要点:

  • 兜底只保留一条,避免”前一条遮蔽后一条”。
  • 认证方法统一为 scram-sha-256,与 PG14+ 的密码存储默认保持一致。
  • peer 要求 OS 用户名与数据库角色名相同,运维脚本里注意保持一致。

七、生效与验证

7.1 重载(无需重启)

SELECT pg_reload_conf();

或命令行:

pg_ctl reload -D $PGDATA

7.2 校验规则(PG10+,能直接定位到行号级错误)

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

-- 只列有问题的行
SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;

7.3 连通性实测

psql -h 10.0.0.231 -U postgres -d postgres    # 应命中 10.0.0.231/32 trust,免密
psql -h 10.0.0.231 -U app_user -d appdb       # 应命中兜底,提示输入密码
psql -d postgres                              # 走 socket,按 local 规则

7.4 服务端起监听确认

ss -lntp | grep 5432
# 期望看到 10.0.0.231:5432 或 0.0.0.0:5432,否则检查 postgresql.conf 的 listen_addresses

八、宿主机访问配置(VMware Workstation + NAT 拓扑)

8.1 拓扑事实

VMnet8(NAT)        10.0.0.0/24
    宿主机 VMnet8 适配器     10.0.0.1
    NAT 网关(虚拟路由器)   10.0.0.2      ← guest 的默认网关
    guest 业务网卡           10.0.0.231    ← PostgreSQL 监听在此

VMnet1(Host-Only)  10.0.10.0/24
    宿主机 VMnet1 适配器     10.0.10.1

8.2 关键结论:VMware NAT 与 VirtualBox NAT 语义不同

  • VirtualBox 的 NAT:guest 藏在 NAT 后面,宿主机无法直达,必须做 --natpf1 端口转发。
  • VMware 的 NAT(VMnet8):宿主机上存在一块同名虚拟适配器,与 guest 同处一个虚拟交换网段。宿主机发起的是同网段直连(不经过 NAT 设备的地址转换),因此 只要 VMnet8 适配器位于 10.0.0.0/24 内,宿主机即可直接访问 10.0.0.231,无需端口转发。

换言之,本例中”精力该花在 guest 的 listen_addresses / pg_hba.conf / 防火墙三处”,而不是网络映射。

8.3 宿主机侧先验证网络与端口

# 确认 VMnet8 适配器地址,期望 10.0.0.1/24
Get-NetIPAddress -AddressFamily IPv4 |
  Where-Object { $_.InterfaceAlias -like "*VMnet8*" } |
  Select-Object InterfaceAlias, IPAddress, PrefixLength

# 网络层
ping 10.0.0.231

# 端口层
Test-NetConnection -ComputerName 10.0.0.231 -Port 5432

TcpTestSucceeded : True 说明网络与端口均通,后续失败只可能是认证问题。

若 ping 不通,用 VMware「编辑 → 虚拟网络编辑器」核对:VMnet8 应为 NAT 模式、子网地址为 10.0.0.0、掩码 255.255.255.0,并确认”将虚拟网络连接到”未指向错误的物理网卡。

8.4 guest 侧三件套

① 监听地址(postgresql.conf)

listen_addresses = 'localhost,10.0.0.231'
# 实验环境可写 '*',生产环境不要

修改 listen_addresses 必须重启(pg_ctl restart -D $PGDATA),reload 不生效。

ss -lntp | grep 5432     # 必须能看到 10.0.0.231:5432

② pg_hba.conf:把写错的那条修成真正的网段

宿主机发起的连接,其来源 IP 显示为 10.0.0.1(宿主机 VMnet8 适配器地址)。原先那条 0.0.0.0/24(无效网段,详见第五节第 2 条)应替换为:

host    all     all     10.0.0.0/24     scram-sha-256
# 或精确到单机
host    all     all     10.0.0.1/32     scram-sha-256
  • 不要用 trust:同网段任何主机都可免密以 postgres 超级用户进入。
  • 不要用 md5:PG14+ 默认 SCRAM 密码存储,md5 方法无法校验(详见第五节第 1 条)。

③ 防火墙

firewall-cmd --list-all
firewall-cmd --add-port=5432/tcp --permanent && firewall-cmd --reload
# 临时开放:firewall-cmd --add-port=5432/tcp

④ 重载并校验

SELECT pg_reload_conf();

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

8.5 确认真实来源地址(不要凭猜写规则)

宿主机连接成功后,在 guest 上执行:

SELECT inet_client_addr(), inet_client_port(), usename, datname
FROM pg_stat_activity
WHERE pid = pg_backend_pid();

inet_client_addr() 返回的就是 pg_hba 实际匹配所用的来源地址。若走的是 NAT 端口映射,该值会变成 NAT 网关 10.0.0.2;若是同网段直连,则会显示 10.0.0.1。

8.6 宿主机侧实测

Test-NetConnection -ComputerName 10.0.0.231 -Port 5432
psql -h 10.0.0.231 -p 5432 -U postgres -d postgres

只装了图形客户端(pgAdmin / DBeaver)时:主机 10.0.0.231、端口 5432、库 postgres、用户 postgres,认证方式选密码(SCRAM),不要选 md5。注意别把宿主机本地的 127.0.0.1:5432 实例与 guest 混淆。

8.7 备选 A:改走 Host-Only 网段 10.0.10.0/24(长期更稳)

NAT 网段依赖 VMware DHCP,guest IP 可能漂移;Host-Only 不依赖外部网络,拓扑更干净,也便于后续加备库、加实验机。

  1. 关机,给虚拟机加第二块网卡,模式选「仅主机(Host-Only)」,自定义网络指向 VMnet1。
  2. 在 guest 内配置静态 IP:
nmcli con add type ethernet conname hostonly ifname eth1 \
      ipv4.method manual ipv4.addresses 10.0.10.101/24
nmcli con up hostonly
ip addr show eth1
  1. 修改监听地址(重启生效):
listen_addresses = 'localhost,10.0.0.231,10.0.10.101'
  1. pg_hba 追加:
host    all     all     10.0.10.0/24     scram-sha-256
  1. 重启 PostgreSQL,防火墙已放行 5432 则无需再改。
  2. 宿主机验证:ping 10.0.10.101 → Test-NetConnection -Port 5432 → psql -h 10.0.10.101 ...。

前提:宿主机 VMware Network Adapter VMnet1 必须位于 10.0.10.1/24,否则需在虚拟网络编辑器中把 VMnet1 子网改为 10.0.10.0/24。

8.8 备选 B:vmnetnat.conf 端口映射(仅在直连确实不通时使用)

编辑 C:\ProgramData\VMware\vmnetnat.conf:

[incomingtcp]
15432 = 10.0.0.231:5432
Restart-Service -Name "VMware NAT Service" -Force
Test-NetConnection -ComputerName 127.0.0.1 -Port 15432
  • 宿主机端口不要用 5432,避免与宿主机本地 PostgreSQL 实例冲突(本例统一用 15432)。
  • 此方式下 guest 看到的来源是 NAT 网关 10.0.0.2,pg_hba 需额外放行 10.0.0.2/32。
  • 既然宿主机本就在 10.0.0.0/24 内,绕这一圈并不划算,仅作保底。

8.9 排错对照表(宿主机侧视角)

现象根因
ping 10.0.0.231 不通VMnet8 适配器不在 10.0.0.0/24;虚拟网络编辑器配置异常;guest 网卡未”已连接”
ping 通但 Test-NetConnection 失败listen_addresses 未含 10.0.0.231(改后是否重启?);firewalld 拦截;用 ss -lntp 复核
no pg_hba.conf entry for host "10.0.0.1"pg_hba 缺 10.0.0.0/24 或 10.0.0.1/32(原 0.0.0.0/24 那条是无效的)
password authentication failedhba 走 md5,而角色密码为 SCRAM 存储
宿主机 127.0.0.1:5432 能连但不是这个库连到了宿主机本地实例,非 guest;改用 10.0.0.231 或映射端口

8.10 最小改动清单(只求宿主机能连)

  1. 将 pg_hba 中 0.0.0.0/24 trust 改为 10.0.0.0/24 scram-sha-256,SELECT pg_reload_conf();
  2. 确认 listen_addresses 含 10.0.0.231,然后 重启 PostgreSQL
  3. firewall-cmd --add-port=5432/tcp --permanent && firewall-cmd --reload
  4. 宿主机 Test-NetConnection 10.0.0.231 -Port 5432,再 psql -h 10.0.0.231 -U postgres -d postgres

全程不需要端口转发 —— 宿主机的 VMnet8 适配器与 guest 同网段,属于直连。

实操补充:本环境最终确认 firewalld 并未拦截 5432(由客户端报 fe_sendauth 反证 TCP 已建立),但排查时仍应先执行 firewall-cmd --state 确认防火墙是否在运行,再决定是否需要放行。详见第九章 9.6。


九、实操排查记录(2026-11-07 已落地)

9.1 环境事实

项目实际值
数据库版本PostgreSQL 18.6(psql (18.6))
guest 主机名pgcm1
guest 业务网卡10.0.0.231(VMnet8 / NAT 网段)
VMnet8 网关(NAT 虚拟路由器)10.0.0.2
宿主机 VMnet8 适配器10.0.0.1(同网段直连,无需端口转发)
Host-Only 网段10.0.10.0/24(VMnet1)
客户端Windows 宿主机上的 pgAdmin(Register – Server 表单)

9.2 操作时间线(含每一步的判定依据)

#操作实际输出 / 结果判定
1首次追加 host all all 10.0.0.0/24 scram-sha-256 到文件末尾(130 行),pg_ctl reloadserver signaled,日志仅 LOG: received SIGHUP, reloading configuration files语法解析通过,但新行位于 0.0.0.0/0 md5 之后,被遮蔽、实际不生效
2重新排序:注释掉 0.0.0.0/0 md5,把 10.0.0.0/24 提到 0.0.0.0/0 scram-sha-256 之前,pg_ctl reload同上,无 WARNING顺序修正,第 129 行成为本网段的实际生效规则
3SELECT ... FROM pg_hba_file_rules ORDER BY line_number DESC LIMIT 5;130 行 0.0.0.0 scram-sha-256、129 行 10.0.0.0 scram-sha-256、126 行 ::1 trust、125 行 127.0.0.1/32 trust、124 行 local all trust;error 列全空语法无错、顺序正确
4SHOW listen_addresses;0.0.0.0已监听全部接口(PG18 默认即为 * 等价形式)
5ss -lntp | grep 5432LISTEN 0 200 0.0.0.0:5432 0.0.0.0:* users:(("postgres",pid=7855,fd=6))TCP 监听已生效,无需重启
6以 postgres 用户执行 firewall-cmd --list-portsAuthorization failed.(polkit 限制)普通用户无权查防火墙,须 root
7切 root 执行 firewall-cmd --list-ports空输出(命令本身执行成功)未见显式开放端口(后经第 10 步反证:实际未拦截)
8查询 pg_authid.postgres 的 rolpassword 前缀SCRAM密码存储格式与 hba 的 scram-sha-256 匹配
9宿主机 pgAdmin 连接 10.0.0.231:5432(用户名/维护库均为 postgres,Password 留空)见 9.4 的两段报错链路已通,仅客户端未发送密码
10pgAdmin 中开启 Save Password 并填入密码后重连连接建立认证通过,闭环

9.3 最终 pg_hba.conf 尾部实际配置

#  124 行
local   all             all                                     trust
#  125 行
host    all             all             127.0.0.1/32            trust
#  126 行
host    all             all             ::1/128                 trust
#  ...(复制相关三行略)
#  129 行 ← 宿主机(10.0.0.1)实际命中的规则
host    all             all             10.0.0.0/24             scram-sha-256
#  130 行 ← 兜底
host    all             all             0.0.0.0/0               scram-sha-256

# 已注释:host all all 0.0.0.0/0 md5

文件状态:"pg_hba.conf" 130L, 5826C written。

9.4 pgAdmin 报错逐句解读

Unable to connect to server:

connection failed: connection to server at "10.0.0.231", port 5432 failed:
  could not initiate GSSAPI security context:
  No credentials were supplied, or the credentials were unavailable or inaccessible:
  Credential cache is empty

connection to server at "10.0.0.231", port 5432 failed:
  fe_sendauth: no password supplied
报错片段含义是否真因
could not initiate GSSAPI security context ... Credential cache is emptylibpq 默认 gssencmode=prefer,先尝试 GSSAPI 加密连接;Windows 无 Kerberos 票据 → 失败后自动回退否,纯噪声
fe_sendauth: no password suppliedTCP 已建立、服务端已请求认证,但客户端未发送任何密码是

关键判读:fe_sendauth 是客户端侧报错,出现在网络层/端口层/服务端认证请求全部成功之后。它同时反证了三件事:端口可达、listen_addresses 生效、pg_hba 已命中并进入密码认证分支。

根因:pgAdmin 4 在编辑模式下,Password 字段只有在 Save Password = True 时才可编辑(界面上那句灰色提示即此意)。未开启时不会弹密码框,而是直接以空密码发送,必然 no password supplied。

处理顺序(不可颠倒):

  1. 打开 Password 输入框右侧的 Save Password(锁形图标);
  2. 此时 Password 字段才变为可编辑,填入 postgres 的 SCRAM 密码;
  3. 点击 Save;
  4. 重新 Connect。

9.5 消除 GSSAPI 噪声(可选)

在宿主机(pgAdmin 运行环境)设置为用户级环境变量,重启 pgAdmin 生效:

[Environment]::SetEnvironmentVariable('PGGSSENCMODE','disable','User')

之后报错中不再出现 GSSAPI 段落,只剩真实原因,便于判断。

9.6 结论与遗留项

已确认通过

  • pg_hba.conf:语法无误、顺序正确,10.0.0.0/24 排在兜底 0.0.0.0/0 之前(第 129 行 vs 第 130 行)。
  • 监听:listen_addresses = 0.0.0.0,ss 显示 0.0.0.0:5432 LISTEN。
  • 认证格式:postgres 角色密码为 SCRAM,与 hba 方法一致,无 md5/SCRAM 错配。
  • 网络:宿主机经 VMnet8 同网段直连,未使用任何端口转发。
  • firewalld:实际未拦截 5432——由 fe_sendauth 反证 TCP 已握手成功。此前”防火墙待放行”的判断不成立,需以 firewall-cmd --state 的实测状态为准,避免在笔记中留下错误结论。

遗留项(未做,建议后续处理)

  1. local all all trust、127.0.0.1/32 trust、::1/128 trust 仍为免密,本机任意 OS 用户可冒用任意角色(含超级用户)。生产化时应改为 peer + scram-sha-256。
  2. 10.0.0.231/32 trust 仍在,本机自连免密;如需统一认证口径,一并改为 scram-sha-256。
  3. 复制相关三行仅覆盖回环,若后续加备库(10.0.0.x)需显式放行该网段。
  4. 未验证 IPv6 客户端路径;0.0.0.0/0 仅匹配 IPv4。
  5. pg_stat_activity 的 inet_client_addr() 尚未记录实际取值,闭环确认时补一次。

9.7 闭环验收清单(可直接复制)

guest 侧(postgres 用户)

SELECT line_number, type, user_name, address, auth_method, error
FROM pg_hba_file_rules ORDER BY line_number DESC LIMIT 5;

SELECT line_number, error FROM pg_hba_file_rules WHERE error IS NOT NULL;

SHOW listen_addresses;

SELECT rolname,
       CASE WHEN rolpassword IS NULL                THEN 'NULL'
            WHEN rolpassword LIKE 'SCRAM-SHA-256%'  THEN 'SCRAM'
            WHEN rolpassword LIKE 'md5%'            THEN 'md5'
            ELSE 'other' END AS pwd_type
FROM pg_authid WHERE rolname = 'postgres';
ss -lntp | grep 5432
firewall-cmd --state            # 以 root 执行
firewall-cmd --list-ports       # 以 root 执行

宿主机侧(Windows PowerShell)

Get-NetIPAddress -AddressFamily IPv4 |
  Where-Object { $_.InterfaceAlias -like "*VMnet8*" } |
  Select-Object InterfaceAlias, IPAddress, PrefixLength

Test-NetConnection -ComputerName 10.0.0.231 -Port 5432

连接成功后回查来源(pgAdmin Query Tool / psql)

SELECT inet_client_addr() AS client_ip,
       inet_client_port() AS client_port,
       usename, datname
FROM pg_stat_activity
WHERE pid = pg_backend_pid();

期望:client_ip = 10.0.0.1(宿主机 VMnet8 地址)。


十、经验总结

  1. psql 第一个位置参数是 dbname,主机必须用 -h —— 本次故障的唯一根因。
  2. 报 role ... does not exist 说明问题在客户端用户名,不在网络和 pg_hba,可快速排除大范围排查方向。
  3. pg_hba 是首条命中即生效,追加规则前必须确认前面没有吞掉来源的规则;两条 0.0.0.0/0 并存几乎必然有一条是死代码。
  4. md5 认证方法与 SCRAM 密码存储不兼容,PG14+ 环境混写会导致”密码明明对却认证失败”。
  5. CIDR 写错(0.0.0.0/24)不会报错,只会静默失效,改配置后务必用 pg_hba_file_rules 复核。
  6. 改完用 SELECT pg_reload_conf() 生效,pg_ctl restart 不是必需的;但 listen_addresses 变更例外,必须重启。
  7. 不要想当然套用 VirtualBox 的 NAT 结论:VMware 的 VMnet8 让宿主机与 guest 同网段直连,多数”宿主机访问不了 guest 服务”的真实原因是 guest 端监听地址、pg_hba 或防火墙,而不是缺端口映射。
  8. 判断来源 IP 用 SELECT inet_client_addr(); 实测,比按经验推断更可靠 —— pg_hba 规则必须与实际来源地址对齐才生效。
  9. 长期使用优先 Host-Only 网段(如 10.0.10.0/24),可避开 NAT 网段 DHCP 导致的 IP 漂移。
  10. “追加到文件末尾”是 pg_hba 改配置的头号陷阱。sed -i '$a'、>> 追加看似省事,结果落在兜底规则之后,reload 无错、日志无 WARNING,但规则静默失效——这种”看起来成功”的失败最难发现,必须用 line_number 显式核对顺序。
  11. fe_sendauth: no password supplied 是链路已通的好消息:它发生在 TCP 握手与服务端认证请求之后,说明端口、监听、pg_hba 全部 OK,问题只在客户端凭证。不要把它误判为网络或防火墙故障。
  12. GSSAPI 报错是回退噪声:gssencmode=prefer 在 Windows 无 Kerberos 票据时必然失败一次再回退到密码认证;PGGSSENCMODE=disable 可静音,避免掩盖真实原因。
  13. pgAdmin 4 编辑模式下,未开启 Save Password 时密码框不可编辑,客户端会直接以空密码发送。操作顺序固定为:开 Save Password → 填密码 → Save → Connect。
  14. firewall-cmd 由普通用户执行会报 Authorization failed(polkit 限制),须 root;且 --permanent 必须搭配 --reload 才生效。
  15. 最终结论要由实测反证,而不是由中间命令的”看起来正常”推断。本例中 --list-ports 为空曾让人以为防火墙是拦截点,实际被 fe_sendauth 推翻。记录结论时应同时写下推翻它的证据来源。
  16. PostgreSQL 18 环境下 md5 已是淘汰路径,兜底统一用 scram-sha-256,且改动前先查 pg_authid.rolpassword 前缀,避免方法/密码格式错配。
  17. 固定排查顺序可显著降低来回试的成本:客户端参数 → 规则顺序 → 监听地址 → 防火墙 → 密码格式 → 客户端凭证,每一层都有可判定的输出(pg_hba_file_rules / ss / pg_authid / 报错文案)。
赞(0) 打赏
未经允许不得转载:徐万新之路 » PostgreSQL 连接排错与 pg_hba.conf 配置解析

支持快讯、专题、百度收录推送、人机验证、多级分类筛选器,适用于垂直站点、科技博客、个人站,扁平化设计、简洁白色、超多功能配置、会员中心、直达链接、文章图片弹窗、自动缩略图等...

联系我们

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册