问题现象描述
当开发者使用pymysql库的ssl_cert参数建立SSL加密数据库连接时,常见会遇到以下报错:
pymysql.err.OperationalError: (2026, 'SSL connection error: certificate verify failed')
该错误表明客户端无法验证服务器提供的SSL证书有效性,通常发生在以下几种场景:
- 自签名证书未添加到信任存储
- 证书链不完整(缺少中间CA证书)
- 证书已过期或尚未生效
- 主机名与证书CN/SAN不匹配
根本原因分析
SSL/TLS握手过程中,客户端会进行严格的证书验证:
- 信任锚验证:检查证书是否由受信任的CA签发(默认使用系统CA存储)
- 有效期验证:证书必须在有效时间范围内
- 主机名验证:连接的主机名必须匹配证书中的CN或SAN字段
通过Wireshark抓包分析可见,当证书验证失败时,TLS握手会在Server Certificate阶段中断。
解决方案
方案1:禁用证书验证(仅测试环境)
conn = pymysql.connect(
ssl={'cert': '/path/client-cert.pem'},
ssl_disabled=True # 禁用验证
)
⚠️ 生产环境严禁使用此方案,会丧失SSL加密的保护作用
方案2:正确配置证书路径
需确保以下文件路径正确:
ssl={
'cert': 'client-cert.pem',
'key': 'client-key.pem',
'ca': 'server-ca.pem' # 必须包含完整的证书链
}
方案3:调试证书问题
使用openssl验证证书链:
openssl verify -CAfile server-ca.pem server-cert.pem
检查证书详细信息:
openssl x509 -in server-cert.pem -text -noout
高级排查技巧
| 问题类型 | 诊断命令 | 解决方案 |
|---|---|---|
| 证书过期 | openssl x509 -dates | 重新签发证书 |
| 主机名不匹配 | 比对证书SAN与连接URL | 使用正确主机名或配置skip_hostname_verify |
最佳实践建议
- 使用Let's Encrypt等权威CA签发证书
- 定期轮换证书(建议不超过90天)
- 在连接字符串中显式指定ssl_mode参数:
ssl_mode="VERIFY_IDENTITY" # 最严格验证级别