PHP 8.4尚未发布,数据库加密取决于MySQL服务端TLS配置与PDO SSL选项协同;需服务端启用SSL、用户强制REQUIRE SSL,并在PDO连接中正确设置PDO::MYSQL_ATTR_SSL_*证书参数且验证Ssl_cipher非空。

下面直接说清怎么做、为什么、容易错在哪。
确认 MySQL 服务端已启用 TLS 并强制 SSL 用户
客户端加一堆 PDO::MYSQL_ATTR_SSL_* 参数没用,如果服务端没开 TLS,连接会退化为明文,甚至静默失败。
- 登录 MySQL 执行
SHOW VARIABLES LIKE '%ssl%';,确认have_ssl = YES且ssl_cipher非空 - 检查用户是否被要求 SSL:
SELECT user, host, ssl_type FROM mysql.user WHERE user = 'your_user';,应为ANY或X509 - 若未强制,执行
ALTER USER 'your_user'@'%' REQUIRE SSL;+FLUSH PRIVILEGES; - 关键点:仅靠
ssl_mode=REQUIRED(如 DSN 中)不能阻止服务端接受非加密连接;必须服务端REQUIRE SSL才真正强制
PDO 连接时显式指定 SSL 选项(不依赖 DSN 参数)
DSN 中写 sslmode=require 是 PostgreSQL 写法,对 MySQL 无效;PDO MySQL 不解析该参数,只认 PDO::MYSQL_ATTR_SSL_* 系列常量。
- 必须传入完整证书路径(即使服务端证书可信,客户端仍需验证):
PDO::MYSQL_ATTR_SSL_CA、PDO::MYSQL_ATTR_SSL_CERT、PDO::MYSQL_ATTR_SSL_KEY - 生产环境严禁设
PDO::MYSQL_ATTR_SSL_VERIFY_SERVER_CERT => false;它跳过证书校验,等于裸连 - 示例代码片段:
<pre class="brush:php;toolbar:false;">$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::MYSQL_ATTR_SSL_CA => '/etc/php-ssl/ca.pem',
PDO::MYSQL_ATTR_SSL_CERT => '/etc/php-ssl/client-cert.pem',
PDO::MYSQL_ATTR_SSL_KEY => '/etc/php-ssl/client-key.pem',
// 不要加 ssl_mode=... 到 DSN 字符串里,MySQL 驱动忽略它
];
$pdo = new PDO('mysql:host=db.example.com;dbname=app', $user, $pass, $options);
验证连接是否真加密,而非“配置了就等于安全”
很多人配完就认为万事大吉,但网络层可能仍在走明文——必须主动验证。
立即学习“PHP免费学习笔记(深入)”;
- 连接后立即执行 SQL:
SHOW STATUS LIKE 'Ssl_cipher';,返回值必须是非空字符串(如 <code>AES256-SHA),否则没加密 - 抓包验证:用
tcpdump -i any port 3306 -w mysql.pcap,Wireshark 打开后应看不到明文 SQL 或密码字段 - 故意移除
PDO::MYSQL_ATTR_SSL_CA,看连接是否失败;若仍成功,说明服务端没强制 SSL 或客户端未校验证书 - 注意:
$pdo->getAttribute(PDO::ATTR_CLIENT_VERSION)只反映驱动版本,不反映加密状态
证书文件权限与存放位置极易出错
私钥泄露 = 数据库凭据泄露,比密码明文更危险。
- 证书路径绝不能放在 Web 根目录下(如
/var/www/html/ssl/),应放系统级受控路径:/etc/php-ssl/(Linux)或C:\php\ssl\(Windows) - 私钥文件权限必须是
600(仅属主可读写),运行 PHP 的用户(如www-data)必须能读取,其他用户不可见 - 不要硬编码路径;用环境变量注入:
putenv('MYSQL_SSL_CA=/etc/php-ssl/ca.pem'),连接时读getenv('MYSQL_SSL_CA') - CI/CD 流水线中若缺失证书或权限错误,
new PDO()会抛PDOException,但错误信息可能被截断,需提前在日志里捕获完整异常



















