“SSL peer certificate was not ok”是OpenSSL底层拒绝服务端证书链的明确提示,主因是根证书缺失(如仅含R3未含ISRG Root X1)、域名SAN不匹配或路径权限问题,非简单配置错误。

PyMongo 报 SSL peer certificate was not ok 的真实含义
这不是证书“没配好”,而是 OpenSSL 在 TLS 握手阶段明确拒绝了服务端发来的证书链——通常因为根证书缺失、域名不匹配或系统时间偏差。错误信息里 SSL peer certificate was not ok 是 OpenSSL 底层抛出的原始提示,PyMongo 只是透传,真正卡点在证书信任链验证环节。
最常漏掉的 CA 文件完整性检查
填了 tlsCAFile 却仍报错,大概率是文件内容不全。Let’s Encrypt 证书必须同时包含 ISRG Root X1 和 R3 中间证书(旧版 DST Root CA X3 已于 2024 年 9 月被主流工具弃用)。只放 lets-encrypt-r3.pem 不够,必须合并或单独指定 isrgrootx1.pem。
- 验证方式:用
openssl x509 -in ca.pem -text -noout | grep "Issuer\|Subject"确认是否含ISRG Root X1 - 推荐做法:直接用
certifi.where(),它返回的cacert.pem已预置最新完整链 - Windows 路径别用单反斜杠:
C:\certs\ca.pem会被解析失败,改用C:/certs/ca.pem或双反斜杠
主机名校验失败的隐蔽表现
PyMongo 默认开启严格 SAN(Subject Alternative Name)匹配,连接字符串里的域名必须和证书中 DNS: 条目完全一致。例如连 cluster0-abcd123.mongodb.net,但证书只写了 *.mongodb.net,就会触发此错——不是通配符无效,而是没覆盖完整 FQDN。
- 快速验证:运行
openssl s_client -connect cluster0-abcd123.mongodb.net:27017 -servername cluster0-abcd123.mongodb.net 2>/dev/null | openssl x509 -noout -text | grep "DNS:" - 临时绕过(仅调试):加参数
tlsAllowInvalidHostnames=True,通了就说明是 SAN 问题 - 不要用
ssl_cert_reqs=ssl.CERT_NONE:PyMongo 6.0+ 已彻底禁用,会直接抛ValueError
路径与权限导致的静默失效
tlsCAFile 参数看似生效,实则文件根本没被读取。PyMongo 在初始化连接时就尝试加载证书,此时若路径是相对路径、文件不可读、或 Python 进程无权限访问,会静默 fallback 到系统默认 CA(往往过时),最终表现为证书校验失败。
- 必须用绝对路径:
os.path.abspath("./certs/ca.pem")或str(Path("certs/ca.pem").resolve()) - 检查权限:
ls -l certs/ca.pem(Linux/macOS)或icacls certs\ca.pem(Windows) - 避免
~缩写:os.path.expanduser()不会在 MongoClient 初始化时自动触发
SSL peer certificate was not ok 反复出现,且错误信息毫无提示性。调试时优先用 openssl s_client 直接测服务端证书,比在代码里反复试参更可靠。


















