PDO连接MySQL必须通过$options数组配置SSL参数,DSN中sslmode=require被忽略;生产环境需同时设置PDO::MYSQL_ATTR_SSL_CA、PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT=>true和PDO::MYSQL_ATTR_SSL_MODE=>PDO::MYSQL_ATTR_SSL_MODE_VERIFY_IDENTITY,否则Ssl_cipher为空即未加密。

MySQL 用 PDO 连接必须配 PDO::MYSQL_ATTR_SSL_CA 等参数,DSN 里加 sslmode=require 没用
ThinkPHP 6+、Laravel 或原生 PDO 都一样:MySQL 的 SSL 参数不走 DSN 字符串解析,只认 $options 数组里的 PDO::MYSQL_ATTR_* 常量。你写 mysql:host=localhost;dbname=test;sslmode=require,PDO 会直接忽略 sslmode —— 这不是 bug,是 MySQL 驱动的硬性限制。
生产环境必须同时满足三项:
-
PDO::MYSQL_ATTR_SSL_CA指向服务端 CA 证书(/etc/mysql/ssl/ca.pem或 Windows 下C:/phpEnv/MySQL/ssl/ca.pem) -
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT设为true(默认是false,不校验就等于没加密) -
PDO::MYSQL_ATTR_SSL_MODE设为PDO::MYSQL_ATTR_SSL_MODE_VERIFY_IDENTITY(强制校验域名,防中间人)
漏掉任意一项,连接可能成功但实际走明文——SHOW STATUS LIKE 'Ssl_cipher' 会返回空值。
phpEnv 下别调 mysqli::ssl_set(),直接传 MYSQLI_CLIENT_SSL 标志
phpEnv 是 Windows 环境,MySQL 默认关闭 SSL,且 mysqli::ssl_set() 在这里极易触发 tlsv1 alert unknown ca 错误。根本原因不是证书错,而是 phpEnv 的 MySQL 没配服务端证书,或者你传了客户端证书路径但服务端根本没要求双向认证。
立即学习“PHP免费学习笔记(深入)”;
正确做法是两步到位:
- 先确认 MySQL 已启用 SSL:
mysql -u root -p -e "SHOW VARIABLES LIKE 'have_ssl';"返回YES才继续 - PHP 代码中用
mysqli_init()初始化后,real_connect()第 7 个参数直接传MYSQLI_CLIENT_SSL,其他参数留null
示例:
$mysqli = mysqli_init();
$mysqli->real_connect('127.0.0.1', 'user', 'pass', 'db', 3306, null, MYSQLI_CLIENT_SSL);
不要碰 ssl_set(),也不要设 MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT —— 这个标志在 phpEnv 下基本等于主动放弃安全。
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
连接成功后必须查 Ssl_cipher,不能只看 PHP 是否报错
PHP 连接不报错 ≠ 加密生效。很多配置看似完整,但 Ssl_cipher 仍是空的,说明流量还在裸奔。
验证方式只有两个命令(任选其一):
- 连接后执行
SELECT @@session.ssl_cipher;,返回非空字符串才算真加密 - 或直接查状态:
SHOW STATUS LIKE 'Ssl_cipher';,值为TLS_AES_256_GCM_SHA384类似内容才对
如果返回空,立刻检查三处:MySQL 的 my.ini 是否写了 ssl-ca 路径且文件真实可读;PHP 进程是否有权限读取该路径;PDO 或 MySQLi 是否漏掉了校验开关(尤其是 PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => true 这个默认为 false 的坑)。
SQL Server 要设 Encrypt=true 和 TrustServerCertificate=false
PHP 连 SQL Server(MSSQL)走 sqlsrv 或 PDO_SQLSRV 扩展,SSL 开关逻辑和 MySQL 完全不同:它不依赖本地证书文件路径,而是靠连接字符串参数控制。
关键两点:
-
Encrypt=true必须显式声明,否则即使 SQL Server 强制加密,PHP 客户端也不发起 TLS 握手 -
TrustServerCertificate=false表示信任系统 CA 库,而不是跳过校验(设true就退化成明文风险)
完整 DSN 示例:
sqlsrv:server=localhost;Database=mydb;Encrypt=true;TrustServerCertificate=false;
Windows 下要确保系统根证书库已更新(尤其自签名证书),Linux 则需把 CA 证书合并进 /etc/ssl/certs/ca-certificates.crt 并运行 update-ca-certificates。


















