PostgreSQL 18.4 SCRAM-SHA-256 认证故障诊断及修复办法

环境:龙蜥 Anolis OS 8.5 (kernel 5.10.134) / PostgreSQL 18.4 源码编译 / 生成时间 2026-07-14


目录


一、结论摘要

核心判断 :你的 postgresql.confpg_hba.conf 配置本身是正确的password_encryption = scram-sha-256scram-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% --- 最常见)

这是最经典的坑。完整时间线如下:

  1. initdb 初始化数据库,此时 password_encryption 可能为默认值

  2. 你在某个时刻为用户设置了密码(ALTER USER postgres PASSWORD 'xxx'

  3. 设置密码时,password_encryption 可能还是 md5(或者你尚未重启使新配置生效)

  4. 密码被以 md5 前缀的哈希格式存入 pg_authid

  5. 你修改 postgresql.confpassword_encryption = scram-sha-256

  6. 你修改 pg_hba.conf 设认证方式为 scram-sha-256

  7. 但你没有重新设置密码! 旧密码仍然是 MD5 哈希

  8. 客户端连接 → 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.confhost 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自动生成,在我的环境上完美的解决了问题。

相关推荐
熊文豪1 小时前
给国产数据库装上中文搜索引擎:zhparser vs jieba 分词实战,与三个隐藏关卡
数据库·搜索引擎·电科金仓
狂师2 小时前
测试人员必备:推荐一款智能测试数据清理AI Skill,支持db、redis、mq等
数据库·aigc·测试
疯狂打码的少年2 小时前
【软件工程】需求工程:需求获取与需求分析
数据库·笔记·软件工程·需求分析
Database_Cool_2 小时前
阿里云 PolarDB-X vs TiDB 分布式数据库选型指南
数据库·分布式·阿里云·tidb
数据库小学妹2 小时前
分布式数据库架构怎么选?三种路线对比+迁移避坑指南
数据库·分布式·分布式数据库·数据库架构·数据迁移·数据库选型
陈同学xxx2 小时前
Hermes Agent 接入飞书,在手机上随时聊天
linux·python·飞书
桑榆肖物2 小时前
在 .NET MAUI 里接入 PP-OCRv6 文本检测实现查找并点击
数据库·redis·.net·maui
网络小白不怕黑2 小时前
14.VSFTP服务相关配置
linux·运维·服务器
是摆烂第一名呀2 小时前
RK3576+GMSL摄像头底层适配与调试
linux·arm开发·驱动开发·嵌入式硬件·数码相机