PDO持久连接不支持自动重连,因其仅复用TCP连接而不感知MySQL状态;必须由应用层通过SELECT 1探活或捕获2006/2013错误后重建PDO实例来实现可靠重连。

PDO 持久连接本身不支持断连后自动重连。它只保证“脚本结束时不关闭连接”,但不会监听网络中断、MySQL 重启或超时断开等事件,也不会在下次 query() 前主动探测连接有效性。所谓“自动重连”必须由应用层显式实现。
为什么 PDO::ATTR_PERSISTENT 不能解决断连问题
持久连接(PDO::ATTR_PERSISTENT => true)只是让 PHP 进程复用已建立的 TCP 连接,避免每次新建握手开销。但它:
- 不感知 MySQL 进程是否存活(比如 MySQL 服务被 kill 或崩溃)
- 不处理
MySQL server has gone away这类错误(错误码2006) - 不触发重连逻辑——PDO 在连接失效后直接抛出
PDOException,而非静默重建 - 在 PHP-FPM 的每个 worker 进程中独立维护连接池,重启 PHP-FPM 或 MySQL 后,旧连接句柄全部失效
PHP7.4 中可行的重连策略(非透明,需编码)
你必须在执行查询前做连接健康检查,或捕获异常后重建 PDO 实例。常见做法有:
- 对关键查询使用
try/catch包裹,捕获PDOException并判断错误码是否为2006(server has gone away)、2013(lost connection)等,然后重新 newPDO - 在每次 query 前调用
$pdo->getAttribute(PDO::ATTR_CONNECTION_STATUS)—— 但注意:该方法在 PHP7.4 中**不可靠**,返回值常为unknown,不建议依赖 - 更稳妥的方式是执行一条轻量语句(如
SELECT 1)做探活,失败则重建连接;但要注意避免在事务中误执行 - 若用的是 Workerman 或 Swoole 长驻进程,应在
onWorkerStart初始化 PDO,并在onWorkerStop清理;同时配合心跳检测(如定时ping)+ 异常捕获,在连接失效时主动unset当前$pdo并重建
容易踩的坑:持久连接 + 自动重连的组合风险
盲目在异常后重建 PDO 实例,却未清理旧连接状态,会引发资源泄漏或状态污染:
立即学习“PHP免费学习笔记(深入)”;
- 未显式设
$pdo = null就 new 新实例,旧连接可能滞留(尤其在长驻进程中) - 重连后未重置会话变量(如
SET NAMES utf8mb4),导致后续查询字符集错乱 - 在事务中发生断连,重连后继续 commit,实际操作的是新连接上的空事务,造成逻辑错误
- 多个并发请求同时触发重连,可能创建大量冗余连接,压垮 MySQL 的
max_connections
真正可靠的方案不是“让 PDO 自动重连”,而是把连接生命周期管理收归应用层:明确何时初始化、何时探活、何时销毁、何时重建,并始终假设任何一次 query() 都可能失败——这才是 PHP7.4 下持久连接在生产环境能稳定跑下去的关键。



















