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自动生成,在我的环境上完美的解决了问题。

相关推荐
爱丶狸9 小时前
Grafana_Zabbix_ImageRenderer_部署与前端操作手册
linux·前端·zabbix·grafana·kylin
k4m7v2pz10 小时前
把 Bevy 0.14 游戏移植到 R36S 掌机:一场与“无窗口系统“的搏斗
linux·rust·bevy·r36s·rk3326·开源掌机
木子欢儿11 小时前
Intel 架构的 MacBook Pro 运行 Linux 发热量高解决
linux·运维·服务器
凌虚11 小时前
面向 MySQL 用户的 PostgreSQL 快速上手指南
数据库·后端·架构
五阿哥永琪11 小时前
MySQL中操作json的函数!
数据库·mysql·json
来者皆善12 小时前
了解Mysql优化吗?如何优化索引?
数据库·mysql
赤壁小虾14 小时前
【渲染流水线】[逐片元阶段]-[透明度测试]以UnityURP为例
java·前端·数据库
MC皮蛋侠客14 小时前
SQLAlchemy 系列(七):高级建模与高效写入——批量 DML、方言与扩展
数据库·python
会编程的土豆14 小时前
Go 模板初识
linux·运维·服务器
奈斯先生Vector15 小时前
把 Midjourney 二次编辑做成生产系统:customId 能力令牌、Action Graph 与 WebUI 精修工作台
数据库·人工智能·架构·aigc·音视频·midjourney