MySQL连接泄漏表现为Sleep连接持续堆积致max_connections耗尽;需通过processlist定位高连接数客户端、对比max_sleep_sec与max_idle_time判断回收失效,并结合Hyperf连接池指标差值、事务未提交/手动PDO未释放/协程长连接三类代码模式及leak_detection告警堆栈精准定位泄漏源。

Hyperf 中 MySQL 连接泄漏不是“连不上”,而是连接不断堆积、长期处于 Sleep 状态,最终耗尽 MySQL 的 max_connections,报 Too many connections。排查关键在“找谁 leaked、怎么 leaked、漏多久了”。
看 MySQL 实时连接分布,定位泄漏源头
登录 MySQL,执行:
SELECT SUBSTRING_INDEX(host, ':', 1) AS client_ip, user, COUNT(*) AS conn_count, MAX(time) AS max_sleep_sec FROM information_schema.processlist WHERE state = 'Sleep' GROUP BY client_ip, user ORDER BY conn_count DESC LIMIT 10;
重点关注:
- 哪个 user(对应 Hyperf 配置里的 username)连接数异常高;
- max_sleep_sec 是否远超你设的 pool.max_idle_time(比如配置了 30 秒,却看到 300+ 秒的 Sleep)——说明空闲回收失效或连接根本没归还。
查 Hyperf 连接池真实使用状态
在业务中注入 Hyperf\DbConnection\Pool\PoolFactory,打印实时指标:
-
$pool->getCurrentConnections():当前总连接数(含活跃 + 空闲) -
$pool->getConnectionsInChannel():真正空闲可分配的连接数 -
$current - $idle就是“正在被占用但未释放”的连接数
如果该差值持续增长、不回落,基本确认存在泄漏。可在定时任务里每分钟采集一次,绘制成监控曲线。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
盯住三类高危代码模式
泄漏往往藏在异常路径或协程生命周期边缘:
-
事务未正常结束:用了
$db->beginTransaction()却没配对commit()或rollback(),尤其在try/catch中 catch 后直接 return,忘了回滚 -
手动获取 PDO 后未归还:调用
Db::getPdo()或$pool->get()后,忘记$pool->release($pdo)或没用finally包裹 - 协程长生命周期场景:如 WebSocket 连接、定时任务协程里复用 DB 连接,但没做连接超时或主动 close,导致连接被“钉死”在协程上下文中
开启并验证连接泄漏检测
在 config/autoload/databases.php 的 pool 配置中启用:
'pool' => [ // ... 'leak_detection' => true, 'leak_threshold' => 60, // 单位:秒,连接被占用超60秒未归还即告警 ],
同时确保日志级别够高(DEBUG),泄漏发生时会输出类似:
[WARNING] Connection leak detected: connection held for 78.2s by coroutine #12345这个协程 ID 可结合 Coroutine::id() 日志追踪到具体业务逻辑位置。

















