PostgreSQL 输入密码后仍报 Peer authentication failed
psql 输入密码后仍报 Peer authentication failed,可能是本机 socket 连接先匹配了 peer 规则。核对连接方式、目标实例和 pg_hba.conf 顺序,保留管理员通道,再按需调整指定角色的 SCRAM 认证。
已经给 PostgreSQL 角色设置了密码,连接时也输入了密码,结果仍然是:
FATAL: Peer authentication failed for user "app_user"
有时甚至已经在 pg_hba.conf 里增加了密码认证规则,重载后仍报同样的错误。先确认这次连接命中了哪条认证规则。peer 核对的是发起本机连接的操作系统用户身份;数据库密码正确,并不能让不匹配的 peer 认证通过。
本文针对 Linux 上通过 Unix-domain socket 连接 PostgreSQL 的场景。下面的诊断 SQL 和 SCRAM 配置适用于 PostgreSQL 18;使用其他版本时,需核对视图字段及客户端对 SCRAM 的支持。app_user、app_db、端口 5432 和 socket 目录均为示例值,请换成实际目标。
密码提示不代表服务器采用了密码认证
下面这条命令会提前提示输入密码:
psql -U app_user -d app_db -W
-W 只要求 psql 在连接前询问密码,即使服务器随后完全不使用它,也会出现提示。认证方式由服务器为这次连接选中的规则决定。
在 Linux 上,没有通过连接参数或环境设置指定主机时,psql 通常会连接本机 Unix-domain socket。此时 pg_hba.conf 中的 local 规则参与匹配;写着 127.0.0.1/32 的 host 规则并不匹配这种连接。
例如,Linux 用户 deploy 执行 psql -U app_user。如果命中的规则使用 peer,并且没有配置相应用户名映射,服务器拿到的是操作系统用户 deploy,而请求登录的数据库角色是 app_user,两者不匹配。-U 指定数据库角色,不会把运行 psql 的 Linux 用户也切换过去。
数据库角色和操作系统账号是两套身份。给数据库角色设置密码,或者更换当前 Linux 用户的登录密码,都不会改变上面的匹配关系。需要 peer 用户映射时应单独配置映射规则;不必为了让业务角色使用数据库密码登录,就创建同名 Linux 账号。
先固定连接方式,再核对实际配置文件
对比连接时,显式写出地址、端口、角色和数据库,避免两次命令访问了不同实例。执行前也要核对是否设置了 PGHOST、PGHOSTADDR、PGPORT 或 PGSERVICE 等连接默认值,尤其不要让隐藏的服务配置把排查目标带到别处。
如果目标是 Ubuntu 上常见的本机 socket 目录,可用:
psql -h /var/run/postgresql -p 5432 -U app_user -d app_db -W
-h 后面以斜杠开头的目录表示 Unix-domain socket,并不是 TCP 主机名。目录不存在或实例使用了其他路径时,应换成实际 socket 目录;报“文件不存在”与本篇的认证失败不是同一问题。
若应用本来就要通过本机 TCP 使用密码认证,可比较:
psql -h 127.0.0.1 -p 5432 -U app_user -d app_db -W
这个连接会按 TCP 对应的 HBA 规则匹配。它只有在目标实例监听本机 TCP、规则允许该角色和数据库、密码认证条件满足时才会成功。改用 TCP 并不等于修好了原来的 socket 连接;不要为了本机登录把监听地址改成全部网卡,或放开所有来源地址。
通过已有的管理员连接,查看服务器实际使用的文件。Ubuntu 安装保留了 postgres 系统账号和管理员 peer 规则时,可从该账号连接;示例仍显式指定实例:
sudo -u postgres psql -h /var/run/postgresql -p 5432 -d postgres
这里若出现 sudo 密码提示,核验的是 sudo 授权,不是数据库角色密码。没有这条管理通道时,使用已有的授权管理方式,不要临时把认证改成 trust 来绕过。
在管理员 psql 会话中执行:
SHOW server_version;
SHOW hba_file;
SHOW port;
SHOW unix_socket_directories;
以 HBA 文件查询返回的路径为准,不要仅凭安装目录里某个 pg_hba.conf 的名字修改配置。一台机器有多个 PostgreSQL 版本或实例时,改错文件不会改变这次连接的认证行为。
密码规则写在 peer 后面,不会作为第二次尝试
假设文件中有以下顺序:
local all all peer
local app_db app_user scram-sha-256
连接 app_db 的 app_user 已经被第一行的 local all all 匹配。PostgreSQL 随即执行 peer 认证;即使认证失败,也不会继续尝试第二行的密码认证。
需要让这一个角色在这一个数据库上使用 socket 密码认证时,可以把特定规则放在宽泛规则之前,同时保留管理员原有的 peer 通道。例如:
local all postgres peer
local app_db app_user scram-sha-256
local all all peer
这是顺序示例,应与现有规则合并,不是整份文件的替代品。尤其要保留原有的限制规则和其他业务规则,不能为了让新规则先匹配而无视已有安全策略。若用了包含文件,规则在包含位置展开,实际顺序也要一起核对。
管理员可以查看当前磁盘文件中的规则:
SELECT rule_number, file_name, line_number,
type, database, user_name, address, auth_method, error
FROM pg_hba_file_rules
ORDER BY rule_number NULLS LAST, file_name, line_number;
按连接类型、数据库、角色和适用地址逐条比较,找到第一条匹配项。error 非空的行需要先修正。这张视图默认只允许超级用户读取,而且反映的是当前文件内容,不是服务器上一次成功加载的规则快照;看到顺序正确,还不能省略重载和新连接验证。
使用 SCRAM 前确认密码存储和客户端支持
规则改成 scram-sha-256 后,角色也需要有可用于 SCRAM 的密码,客户端库必须支持 SCRAM。如果角色仍只保存旧的 MD5 密码摘要,仅改 HBA 的方法名可能使错误变成密码认证失败。
已确认密码按 SCRAM 保存时,无需为了排查顺序问题反复重设密码。确实需要转换时,先确认所有使用这个角色的应用客户端兼容,并安排好凭据更新。在授权管理员 psql 会话中可对指定角色执行:
SET password_encryption = 'scram-sha-256';
\password app_user
按提示输入该角色应使用的密码。这里的 SET 只影响当前会话之后设置密码时采用的方式,不会自动转换其他角色的已有密码。使用交互式 \password 可避免把明文密码直接写进 SQL 命令历史。
如果同时换了密码,应用保存的凭据也要更新;认证规则回退不会把密码恢复成旧值。不要从旧配置示例直接照搬 MD5 作为新的默认方案:PostgreSQL 18 已将 MD5 密码支持标为弃用,后续版本计划移除。
重载后用新连接验收
修改前备份实际 HBA 文件及涉及的包含文件,并保留当前管理员会话。先查看 pg_hba_file_rules 中是否有解析错误,再在有权限的会话中执行:
SELECT pg_reload_conf();
Linux 上修改 HBA 后需要让服务器重新读取配置,无需仅为这项修改重启整个数据库。返回 true 表示重载信号发送成功,不能据此断言每条配置都已正确加载;还需查看服务器日志中的重载或解析错误。
打开另一个终端,使用之前失败的同一条 socket 连接命令重新连接。登录后核对:
\conninfo
SELECT current_user, current_database();
确认连接确实走了预期的 socket,角色和数据库也正确,再检查实际业务所需的操作。已有连接不会重新走一遍认证,不能用“旧窗口还能查询”作为新规则已生效的证据。
如果错误仍是 Peer authentication failed,继续检查第一条匹配规则、包含文件顺序、目标实例和是否成功重载。若错误变成 password authentication failed,应转向角色密码和认证方法兼容性;若变成数据库连接权限或表权限错误,则认证之后的授权还需要单独处理,不要把角色直接提升为超级用户。
需要回退时,从备份恢复本次修改的文件,检查解析结果,再通过保留的管理员通道重载,并另开连接确认原有业务恢复。只移动了特定规则,就按原顺序恢复;若做过密码转换或更换,还需一并核对应用凭据,避免把配置回退误当成密码回退。


