问题描述
单PG13容器、数据卷不清空、保留业务数据、本地免密+远程强制密码、改密码不生效、旧密码仍可登录、新密码远程报错全套问题根因与标准解决流程
环境基线:Docker PostgreSQL 13、持久化数据卷、Python3.6+Airflow(老旧psycopg2不支持SCRAM)、离线极简容器(无ip/ifconfig命令)
开始情况为docker内的pg用户密码强度不够,需要修改密码。正好遇到端口号问题。直接重建容器,保留数据卷。指定新端口和高强度密码。
后续发现密码没有生效,进入容器修改密码,全程无报错,但是经测试验证失败。
核心问题总览(本次所有故障现象)
现象1:执行 ALTER USER 改密码看似成功,远程旧密码依然能登录、新密码报错
现象2:仅单独执行改密码语句不生效,不彻底
现象3:Docker 启动环境变量 POSTGRES_PASSWORD 修改无效
现象4:容器内裸psql可以免密登录,远程连接需要密码(业务所需配置)
现象5:Airflow 连接PG认证失败,SCRAM加密不兼容老旧驱动
最关键底层原理
Docker PG 环境变量只生效一次
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB
仅在数据卷为空、首次初始化生效。
一旦挂载目录已有PG数据文件:无论重启/重建容器、怎么改环境变量,密码完全不变。
已有数据只能用 SQL 改密码,环境变量永久失效。
PG13 默认加密坑(新旧密码共存元凶)
PG13 默认加密:scram-sha-256
Airflow Python3.6 自带 psycopg2 不支持 SCRAM,只支持 MD5。
单独执行 ALTER USER 密码 的致命问题:
只改当前会话加密,未全局持久化
数据库仍然保留旧密码 SCRAM 哈希
新密码存为 SCRAM,老旧驱动不识别 → 新密码报错
旧哈希未覆盖 → 旧密码依然能登录
pg_hba.conf 认证规则优先级高于密码
如果外网规则为 trust:无视密码、新旧密码全部放行,改密码等于白改。
业务标准需求:本地socket免密、远程TCP强制密码
标准化正确改密码流程
适用:PG13、已有数据、不删库、保留业务、兼容Airflow
步骤1:进入容器本地免密登录
无需密码,直接本地socket登录:
1 | docker exec -it 你的pg容器名 psql |
步骤2:成套执行(必须全部执行,缺一不可)
1 | -- 1. 全局永久修改加密方式为 md5(写入配置文件,重启不失效) |
步骤3:验证密码哈希是否真正更新(核心校验)
1 | SELECT rolname, rolpassword FROM pg_authid WHERE rolname='postgres'; |
严格验证方法(区分真假生效)
重点:裸psql本地登录不算验证!必须走TCP网络连接
- 本地免密验证(符合业务需求)
直接 psql 可登录 ✅
- 远程TCP验证(模拟Airflow/所有外部业务)
1 | psql -U postgres -h 10.X.X.1 -p 5432 -W airflow |
所有错误操作汇总
错误1:只执行单条改密码
1 | ALTER USER postgres WITH PASSWORD 'xxx'; |
后果:加密模式未切换、旧哈希残留、新旧密码共存、远程报错
❌ 错误2:修改docker run 环境变量密码
已有数据卷完全无效
❌ 错误3:pg_hba 保留 trust 规则
后果:所有密码校验失效,任何人免密登录
❌ 错误4:仅会话级设置加密
1 | SET password_encryption = md5; |
仅当前窗口生效,全局不变,重启复原
最终根治总结
PG13改密码旧密码还能登、新密码报错,100%是未全局切换MD5加密导致新旧哈希共存;必须 ALTER SYSTEM 全局改加密 + 重载 + 重设密码,配合pg_hba远程md5校验,才能彻底修复。