PHP数据库连接由底层扩展与MySQL建立TCP连接,生命周期取决于进程模型、连接模式及资源释放时机;FPM短连接请求结束自动清理,持久连接易因状态残留引发错乱,CLI/Swoole等长进程需手动管理。

PHP 的数据库连接不是由 PHP 自身“管理”的,而是依赖底层扩展(mysqli 或 PDO)与 MySQL 服务器建立 TCP 连接,并由操作系统和数据库服务共同维持。你写的代码只是触发连接动作,真正生命周期控制在进程、连接模式和资源释放时机这三层上。
PHP-FPM 请求周期内连接自动释放的真相
在传统 Apache + mod_php 或 PHP-FPM 场景下,每个 HTTP 请求运行在一个独立进程中(或线程中)。只要你没显式使用持久连接,$mysqli 或 $pdo 对象在脚本执行完毕后会被销毁,底层 socket 连接由操作系统关闭——这不是 PHP 主动“管理”,而是进程退出时的自然清理。
- 不调用
$conn->close()或将$pdo = null通常不会泄漏连接(短连接场景下) - 但若在循环里反复 new
PDO却不 unset,可能在单次请求中耗尽本地可用端口(尤其高并发时) -
max_connections是 MySQL 侧限制,不是 PHP 能绕过的;PHP 进程数 × 每个请求的连接数,必须小于该值
持久连接(pconnect)为什么容易出问题
当你启用 PDO::ATTR_PERSISTENT 或 mysqli::real_connect() 带 MYSQLI_CLIENT_FOUND_ROWS 标志时,连接不会随脚本结束而关闭,而是被放回连接池供后续请求复用。但这个“池”是 PHP 进程级的,不是全局的。
- FPM worker 进程重启前,同一个进程里的多次请求可能拿到同一个物理连接
- 事务未提交、临时表未清理、用户变量残留,都会影响下一个请求——这是最常见的数据错乱来源
- 不同用户会话共享连接时,
SET NAMES、SQL_MODE等会话变量可能串扰 - MySQL 的
wait_timeout仍会断开空闲持久连接,PHP 不会自动重连,下次使用直接抛PDOException
CLI/Swoole/长进程场景必须手动管理连接
在命令行脚本、Swoole Worker、ReactPHP 或其他常驻进程环境中,PHP 不再按请求周期回收资源。此时连接生命周期完全由你控制,不关就真不关。
立即学习“PHP免费学习笔记(深入)”;
-
$pdo对象即使超出作用域,只要还有引用(比如被闭包捕获、存入静态属性),就不会析构 - 推荐显式赋值
$pdo = null,而不是依赖 GC;对mysqli则应调用$mysqli->close() - 若需复用连接,建议封装成连接工厂 + 单例 + 心跳检测(例如执行
SELECT 1),避免拿到已失效的连接 - 不要在 Swoole
onWorkerStart中一次性创建所有连接并全局存储——连接可能在 worker 重启后失效,且无法感知 MySQL 主从切换
真正的“管理”不在 PHP 语法层面,而在你是否清楚当前运行模型(FPM?CLI?协程?)、连接类型(短连?持久?)、以及连接对象的引用链是否被意外延长。漏掉任何一个,都可能让连接卡在 TIME_WAIT、被 MySQL 主动 kill,或者在日志里看到 Too many connections。



















