通过PgBouncer连接未开启SSL的PostgreSQL遇'received unencrypted data'问题求助
问题背景
我们的架构是Go客户端(基于github.com/jackc/pgx/v5/pgxpool)通过PgBouncer连接未开启SSL的PostgreSQL:
- PgBouncer未配置SSL相关参数,
server_tls_sslmode默认值为prefer - Go客户端未设置SSL参数,pgx默认
sslmode也为prefer
但偶发出现以下异常:
- PostgreSQL侧报错:
FATAL,08P01,"received unencrypted data after SSL request","This could be either a client-software bug or evidence of an attempted man-in-the-middle attack." - PgBouncer侧报错:
pooler error: server login has been failing, try again later (server_login_retry) - 客户端侧报错:
FATAL: server login has been failing, try again later (server_login_retry) (SQLSTATE 08P01)
错误仅持续短时间,但客户端感知连接不可用时长较长,推测与PgBouncer默认server_login_retry=15秒有关,且PostgreSQL视角下PgBouncer连接全部断开,暂无法稳定复现。
组件版本信息:
- PostgreSQL:
postgres (PostgreSQL) 15.6 (Ubuntu 15.6-1.pgdg20.04+1) - PgBouncer:
1.23.1(依赖libevent 2.1.12-stable、OpenSSL 1.1.1n)
解决思路与建议
1. 强制禁用SSL,消除协商不确定性
由于PostgreSQL未开启SSL,直接跳过SSL协商可以彻底避免这类异常:
- PgBouncer配置:在
pgbouncer.ini中添加server_tls_sslmode=disable,重启PgBouncer生效 - Go客户端配置:在连接串中明确指定
sslmode=disable,例如:connStr := "postgres://user:pass@pgbouncer-host:port/dbname?sslmode=disable" pool, err := pgxpool.New(context.Background(), connStr)
解释:prefer模式下,组件会先尝试SSL握手,失败后降级明文,但网络波动或组件协商逻辑的偶发冲突可能导致握手过程异常,直接禁用SSL可规避这类场景。
2. 调整PgBouncer重试参数,缩短不可用窗口
修改PgBouncer的连接重试配置,减少客户端等待时间:
- 临时设置
server_login_retry=3(单位:秒),降低重连间隔 - 配合设置
server_connect_timeout=5,限制单次连接超时时间
修改后重启PgBouncer,观察客户端感知的不可用时长是否缩短。
解释:默认15秒的重试间隔会导致PgBouncer在连接失败后长时间不尝试重连,这段时间内客户端无法获取可用连接;缩短间隔可加快恢复速度,但需注意不要设置过小导致频繁重试加重PostgreSQL负担。
3. 排查网络层面干扰
这类异常可能由网络问题引发,需验证PgBouncer与PostgreSQL之间的网络稳定性:
- 使用
tcpdump抓取两者之间的流量,出现错误时分析SSL协商阶段的数据包,查看是否存在丢包、包乱序或篡改情况 - 检查中间网络设备(防火墙、负载均衡)是否存在拦截或修改PostgreSQL协议包的规则
解释:"received unencrypted data after SSL request"错误可能是PostgreSQL收到不完整的SSL握手包后,后续收到明文数据导致,这往往和网络丢包或中间设备干扰有关。
4. 升级组件版本修复已知bug
偶发问题可能与组件的已知bug相关,建议升级到最新稳定版:
- 升级PgBouncer到当前最新稳定版本(如1.24.x),查看官方changelog是否有SSL协商相关的修复
- 升级
pgx/v5到最新版本,确认是否存在prefer模式下的握手逻辑修复
5. 监控连接状态定位根因
启用监控实时观察连接池状态,便于问题发生时快速定位:
- 启用PgBouncer的统计接口,查询
pools、stats_users视图,查看连接池的连接失败、重试情况 - 出现错误时,查询PostgreSQL的
pg_stat_activity,查看PgBouncer连接的状态是否异常
内容的提问来源于stack exchange,提问作者darkframexue
相关产品推荐
相关产品推荐

