环境:龙蜥 Anolis OS 8.5 (kernel 5.10.134) / PostgreSQL 18.4 源码编译 / 生成时间 2026-07-14
目录
-
[七、PostgreSQL 18 认证变更须知](#七、PostgreSQL 18 认证变更须知)
一、结论摘要
核心判断 :你的
postgresql.conf和pg_hba.conf配置本身是正确的 。password_encryption = scram-sha-256与scram-sha-256认证方式匹配一致。问题几乎可以确定出在数据库中存储的用户密码哈希格式上------密码要么从未被正确设置,要么是以 MD5 格式存储的,导致 SCRAM 握手时找不到有效的 SCRAM 密钥。
PostgreSQL 的认证机制有一个关键特性:修改 password_encryption 参数不会自动重新加密已有密码 。如果你在某个时间点修改了这个参数,之前已设置的密码仍然保持旧的哈希格式。只有在此参数生效后重新执行 ALTER USER ... PASSWORD,密码才会以新的格式重新存储。
二、配置文件逐行分析
2.1 pg_hba.conf
实际生效的规则(去掉注释后的内容):
| 类型 | 数据库 | 用户 | 地址 | 认证方式 | 说明 |
|---|---|---|---|---|---|
| local | all | all | --- | trust | Unix socket 本地连接 → 免密 |
| host | all | all | 127.0.0.1/32 | trust | IPv4 本地回环 → 免密 |
| host | all | all | 172.22.12.19/24 | scram-sha-256 | 远程网段 → 需密码 |
| host | all | all | ::1/128 | trust | IPv6 本地回环 → 免密 |
| 检查项 | 状态 | 说明 |
|---|---|---|
| scram-sha-256 规则存在 | ✅ 正确 | 172.22.12.0/24 网段已配置 scram-sha-256 |
| CIDR 表示法 172.22.12.19/24 | ✅ 正确 | /24 掩码匹配 172.22.12.0~255 整个网段,.19 为主机位被忽略 |
| 规则顺序 | ✅ 正确 | trust 规则在前(本地),scram 规则在后(远程),互不干扰 |
| listen_addresses | ✅ 正确 | postgresql.conf 中已设为 '*',监听所有网卡 |
注意 :从
127.0.0.1连接时会命中trust规则(免密直接进入),不会触发密码认证。你遇到的"密码认证失败"一定是从 172.22.12.x 网段的远程机器连接时发生的。
2.2 postgresql.conf
认证相关参数:
| 参数 | 值 | 状态 |
|---|---|---|
password_encryption |
scram-sha-256 |
✅ 正确 |
authentication_timeout |
5min |
✅ 正确 |
md5_password_warnings |
on(默认) |
✅ 正确 |
listen_addresses |
'*' |
✅ 正确 |
hba_file |
未设置(使用默认值 $PGDATA/pg_hba.conf) |
⚠️ 需确认编辑的是正确文件 |
log_connections |
未启用 | ❌ 建议临时开启以排查认证问题 |
三、根因分析(四大可能原因)
原因 ①:用户密码从未设置(概率 30%)
源码编译安装时,如果 initdb 没有使用 --pwprompt 或 --pwfile 参数,postgres 超级用户创建后没有密码 。后续如果也没有通过 ALTER USER 设置密码,SCRAM 认证会直接失败,因为数据库中根本没有可用的 SCRAM 密钥(SCRAM secret)。
错误信息通常为:User "xxx" does not have a valid SCRAM secret.
原因 ②:密码以 MD5 格式存储(概率 50% --- 最常见)
这是最经典的坑。完整时间线如下:
-
initdb初始化数据库,此时password_encryption可能为默认值 -
你在某个时刻为用户设置了密码(
ALTER USER postgres PASSWORD 'xxx') -
设置密码时,
password_encryption可能还是md5(或者你尚未重启使新配置生效) -
密码被以
md5前缀的哈希格式存入pg_authid表 -
你修改
postgresql.conf设password_encryption = scram-sha-256 -
你修改
pg_hba.conf设认证方式为scram-sha-256 -
但你没有重新设置密码! 旧密码仍然是 MD5 哈希
-
客户端连接 → SCRAM 握手 → 服务端在 pg_authid 中找不到 SCRAM 格式的密钥 → 认证失败
关键原理 :
password_encryption只影响新设置密码时 使用的加密算法,不会追溯重加密已有密码。修改此参数后,必须对每个用户重新执行ALTER USER ... PASSWORD才能生成 SCRAM 格式的新哈希。
原因 ③:修改 pg_hba.conf 后未重载配置(概率 10%)
pg_hba.conf 的修改不会自动生效,必须执行重载操作。如果你只修改了文件但没重载,PostgreSQL 仍在使用旧的认证规则。
原因 ④:客户端版本过旧不支持 SCRAM(概率 10%)
SCRAM-SHA-256 从 PostgreSQL 10 开始支持。如果客户端使用的 libpq、JDBC 驱动(pgjdbc < 42.2.0)或 psycopg2 版本过旧,不支持 SCRAM 协议,认证也会失败。在龙蜥 8.5 上,如果通过 yum 安装了老版本的 postgresql 客户端包,可能与此源码编译的 18.4 服务端不匹配。
四、诊断步骤(逐条排查)
步骤 1:通过 trust 规则免密进入数据库
从服务器本机执行(会命中 127.0.0.1 trust 规则):
# 切换到 postgres 用户
su - postgres
# 进入 psql(本机连接不需要密码)
/usr/local/pgsql/bin/psql -h 127.0.0.1 -U postgres
如果这一步就失败,说明 PostgreSQL 服务可能未启动或端口不对。
步骤 2:检查 password_encryption 当前值
SHOW password_encryption;
-- 期望输出:scram-sha-256
-- 如果输出 md5,说明配置未生效(需重启或 reload)
步骤 3:检查用户密码哈希格式(最关键!)
-- 查看 postgres 用户的密码存储格式
SELECT rolname, rolpassword
FROM pg_authid
WHERE rolname = 'postgres';
-- 可能的三种结果:
-- 1. rolpassword 为 NULL → 密码从未设置(原因①)
-- 2. 以 md5 开头 → MD5 格式,与 scram-sha-256 不兼容(原因②)
-- 3. 以 SCRAM-SHA-256$ 开头 → SCRAM 格式,配置正确(排除前两个原因)
也可以查看所有用户的密码格式:
SELECT rolname,
CASE
WHEN rolpassword IS NULL THEN '无密码'
WHEN rolpassword LIKE 'md5%' THEN 'MD5格式(不兼容SCRAM)'
WHEN rolpassword LIKE 'SCRAM-SHA-256$%' THEN 'SCRAM格式(正确)'
ELSE '未知格式'
END AS password_format
FROM pg_authid
WHERE rolcanlogin = true;
步骤 4:确认 pg_hba.conf 实际加载的规则
-- 查看 PostgreSQL 实际生效的 HBA 规则
SELECT line_number, type, database, user_name, address, auth_method
FROM pg_hba_file_rules
ORDER BY line_number;
-- 确认 172.22.12.0/24 网段的 auth_method 确实是 scram-sha-256
-- 如果这里看不到你的规则,说明编辑了错误的 pg_hba.conf 文件
步骤 5:确认 pg_hba.conf 文件路径
-- 查看 PostgreSQL 实际读取的配置文件路径
SHOW hba_file;
-- 输出类似:/usr/local/pgsql/data/pg_hba.conf
-- 确认你编辑的就是这个文件!
SHOW config_file;
-- 确认 postgresql.conf 的路径
SHOW data_directory;
-- 确认数据目录
步骤 6:检查客户端版本
# 在客户端机器上执行
psql --version
# 如果低于 10,不支持 SCRAM,需要升级
# 检查 libpq 版本
pg_config --version
# 或
ldd $(which psql) | grep pq
步骤 7:开启日志排查(可选但强烈建议)
-- 在 postgresql.conf 中临时设置
-- log_connections = 'all'
-- log_disconnections = on
-- log_line_prefix = '%m [%p] %u@%d from %h '
-- 重载配置
SELECT pg_reload_conf();
-- 然后从远程尝试连接,查看日志输出
-- 日志文件通常在 $PGDATA/log/ 目录下
-- 或直接在终端查看(如果以 foreground 模式启动)
五、修复方案(完整步骤)
前提 :以下步骤假设你已经通过本机 trust 规则成功进入了 psql。如果连 psql 都进不去,请先将
pg_hba.conf中host all all 127.0.0.1/32改为trust,重启 PostgreSQL,再继续。
方案 A:标准修复流程(推荐)
第 1 步:确认并设置 password_encryption
-- 在 psql 中执行
SHOW password_encryption;
-- 如果不是 scram-sha-256,在当前会话中强制设置
SET password_encryption = 'scram-sha-256';
-- 确认已生效
SHOW password_encryption;
-- 必须输出:scram-sha-256
第 2 步:为 postgres 超级用户重新设置密码
-- 先清空旧密码(关键!避免残留)
ALTER ROLE postgres PASSWORD NULL;
-- 重新设置密码(此时 password_encryption 已为 scram-sha-256)
-- 密码会被自动以 SCRAM 格式存储
ALTER ROLE postgres WITH PASSWORD '你的新密码';
第 3 步:为其他业务用户重设密码
-- 对每个需要远程连接的用户重复操作
ALTER ROLE your_app_user WITH PASSWORD '应用密码';
第 4 步:验证密码格式已正确
SELECT rolname, rolpassword
FROM pg_authid
WHERE rolname = 'postgres';
-- rolpassword 应以 SCRAM-SHA-256$ 开头
-- 例如:SCRAM-SHA-256$4096:salt:hash
-- 如果仍以 md5 开头,说明 SET password_encryption 未生效,回到步骤 1
第 5 步:确保 postgresql.conf 中持久化配置
-- 在 postgresql.conf 中确认(或添加)这一行
-- password_encryption = scram-sha-256
-- 或通过 ALTER SYSTEM 设置(PG 18 支持)
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
第 6 步:确认 pg_hba.conf 并重载
-- 确认 pg_hba.conf 中有这一行(你的配置已正确)
-- host all all 172.22.12.0/24 scram-sha-256
-- 在 psql 中重载配置
SELECT pg_reload_conf();
-- 或在命令行重载
-- /usr/local/pgsql/bin/pg_ctl reload -D /usr/local/pgsql/data
第 7 步:从远程机器测试连接
# 在 172.22.12.x 网段的客户端机器上执行
psql -h 172.22.12.19 -U postgres -d postgres -W
# -W 表示强制提示输入密码
# 输入你在步骤 2 中设置的密码
# 应该能成功连接!
方案 B:initdb 时正确初始化(重新部署参考)
如果你需要重新初始化数据库,务必使用以下参数:
# 使用正确的 initdb 参数
/usr/local/pgsql/bin/initdb \
-D /usr/local/pgsql/data \
-E UTF8 \
--locale=en_US.UTF-8 \
--auth-host=scram-sha-256 \
--auth-local=trust \
--pwprompt
# --auth-host=scram-sha-256 : 生成的 pg_hba.conf 中 host 规则默认使用 scram-sha-256
# --auth-local=trust : 本地 Unix socket 使用 trust(方便管理)
# --pwprompt : 初始化时提示设置 postgres 超级用户密码
# : 此时 password_encryption 默认已是 scram-sha-256(PG18)
# : 所以设置的密码会自动以 SCRAM 格式存储
六、成功案例参考
案例 1:RHEL 8 源码编译 PostgreSQL 16 + SCRAM 认证
# 1. 编译安装
./configure --prefix=/usr/local/pgsql --with-openssl --with-icu
make && make install
# 2. 创建用户和目录
useradd -m postgres
mkdir -p /pg/data && chown postgres:postgres /pg/data
# 3. 初始化(关键参数)
su - postgres
/usr/local/pgsql/bin/initdb -D /pg/data \
-E UTF8 --locale=en_US.UTF-8 \
--auth-host=scram-sha-256 --pwprompt
# 4. 修改 postgresql.conf
# listen_addresses = '*'
# password_encryption = scram-sha-256
# 5. 修改 pg_hba.conf
# host all all 0.0.0.0/0 scram-sha-256
# 6. 启动
/usr/local/pgsql/bin/pg_ctl -D /pg/data -l logfile start
# 7. 远程连接成功
psql -h 服务器IP -U postgres -W
案例 2:PG13 密码 MD5/SCRAM 混乱修复
# 问题:pg_hba 在 md5/scram 间多次切换,密码 hash 损坏
# 修复步骤:
# 1. 临时改为 trust 进入数据库
echo "host all all 127.0.0.1/32 trust" >> $PGDATA/pg_hba.conf
pg_ctl reload -D $PGDATA
# 2. 进入后清洗密码
psql -h 127.0.0.1 -U postgres
SET password_encryption = 'scram-sha-256';
ALTER ROLE postgres PASSWORD NULL;
ALTER ROLE postgres WITH PASSWORD 'newpass';
-- 3. 验证
SELECT rolpassword FROM pg_authid WHERE rolname='postgres';
-- 确认以 SCRAM-SHA-256$ 开头
# 4. 恢复 pg_hba.conf 为 scram-sha-256
# 5. pg_ctl reload
七、PostgreSQL 18 认证变更须知
PostgreSQL 18 于 2025 年 9 月 25 日正式发布。 以下是与你当前问题相关的认证变更:
| 变更项 | 说明 | 对你的影响 |
|---|---|---|
| MD5 认证弃用 | PG18 中 MD5 密码认证被标记为弃用(deprecated),未来版本将完全移除 | 如果密码仍是 MD5 格式,日志会输出弃用警告。必须迁移到 SCRAM |
md5_password_warnings 新参数 |
默认开启。当 CREATE ROLE / ALTER ROLE 存储了 MD5 密码时,在日志中输出警告 | 检查 PostgreSQL 日志是否有此警告,可以确认密码是否为 MD5 格式 |
| SCRAM 透传认证 | postgres_fdw 和 dblink 支持 SCRAM 透传,无需在用户映射中存储密码 | 如果你使用了 FDW 跨库连接,此特性可简化配置 |
| OAuth 认证 | 新增 OAuth 2.0 认证方式(通过扩展支持) | 不影响当前问题,但未来可作为认证选项 |
| password_encryption 默认值 | PG18 默认值为 scram-sha-256(自 PG14 起) | 即使不显式设置,新密码也会使用 SCRAM。但显式设置更安全 |
八、配置检查清单
| # | 检查项 | 命令 / 位置 | 期望值 | 你的状态 |
|---|---|---|---|---|
| 1 | password_encryption | SHOW password_encryption; |
scram-sha-256 | ✅ 配置正确 |
| 2 | pg_hba.conf 认证方式 | SELECT * FROM pg_hba_file_rules; |
scram-sha-256 | ✅ 配置正确 |
| 3 | 用户密码哈希格式 | SELECT rolpassword FROM pg_authid WHERE rolname='postgres'; |
以 SCRAM-SHA-256$ 开头 | ❌ 需验证 |
| 4 | pg_hba.conf 文件路径 | SHOW hba_file; |
与你编辑的路径一致 | ⚠️ 需确认 |
| 5 | 配置已重载 | SELECT pg_reload_conf(); |
返回 t | ⚠️ 需确认 |
| 6 | listen_addresses | SHOW listen_addresses; |
* | ✅ 配置正确 |
| 7 | 防火墙放行 5432 | firewall-cmd --list-ports |
5432/tcp | ⚠️ 需确认 |
| 8 | 客户端版本 | psql --version |
≥ 10(推荐 18) | ⚠️ 需确认 |
本方案由AI自动生成,在我的环境上完美的解决了问题。