Hyperf MySQL断线重连“没反应”的根本原因是连接未进入重连逻辑:wait_timeout过小导致协程排队超时抛异常,heartbeat与max_idle_time配错致僵尸连接不清理,ATTR_TIMEOUT未设使慢查询长期占连接,pipeline/multi未exec引发连接泄漏。

Hyperf 里 MySQL 断线重连“没反应”,不是客户端不重连,而是连接根本没机会走到重连逻辑——它卡在连接池排队或复用僵尸连接阶段。
pool.wait_timeout 设太小,协程连连接都拿不到
wait_timeout 是协程在连接池里等空闲连接的最长容忍时间。设成 0.5 或 1.0,QPS 一抖动,大量协程瞬间超时抛出 WaitTimeoutException,根本没走到数据库操作那步,更别说触发重连。
- 现象:日志满屏
Hyperf\Pool\Exception\WaitTimeoutException,但SHOW PROCESSLIST显示 MySQL 实际连接数远低于max_connections - 原因:不是池子不够,是协程等不及就放弃了;重连机制压根没被调用
- 建议值:从
3.0起步,压测下峰值并发时的平均等待耗时,最终定为2.0~5.0区间 - 验证:用
swoole_get_local_socket_count()或ss -s | grep ESTAB看 ESTABLISHED 连接是否长期贴近max_connections;如果不是,说明问题不在池容量
heartbeat 和 max_idle_time 配反了,僵尸连接永远不被清理
Hyperf 的 pool.heartbeat 不是“开就灵”,它只对空闲连接生效,且必须和 max_idle_time、MySQL 服务端的 wait_timeout 构成严格大小关系: heartbeat < max_idle_time < MySQL wait_timeout。配错一个,心跳就失效。
- 常见错误:MySQL
wait_timeout = 300,却把max_idle_time设成600→ 连接在池里“睡过头”,取出即报2006 MySQL server has gone away - 典型误配:
heartbeat = 5→ 每 5 秒狂发 PING,MySQL 压力陡增,还可能被防火墙拦截 - 正确做法:查 MySQL 实际值(
SHOW VARIABLES LIKE 'wait_timeout'),设max_idle_time = wait_timeout - 30,heartbeat = max_idle_time / 2 - 注意:
heartbeat必须是正整数(如135),设true或-1都不生效
options.ATTR_TIMEOUT 没设,慢查询拖垮整个连接
options.ATTR_TIMEOUT 是 PDO 层级的执行超时,单位秒。不设它,一条慢 SQL 就能让连接卡死几十秒,期间该连接无法归还池子,还会导致后续协程排队超时,形成连锁假象。
- 后果:单条慢查询引发连接池雪崩,监控看到的是“连接耗尽”,实际是连接被占着不动
- 与
pool.wait_timeout区别:wait_timeout控制“等连接”的时间,ATTR_TIMEOUT控制“用连接执行 SQL”的时间 - 推荐值:
3(3 秒),比 Nginx 的 fastcgi_read_timeout 或前端超时更短,确保快速失败 - 必须配合事务使用:长事务内执行多条 SQL,每条都受此限制;若需放宽,应在业务层显式控制,而非全局调大
pipeline/multi 后未 exec,连接泄漏直接废掉整个池
Hyperf 中 $mysql->pipeline() 或 $mysql->multi() 返回的是当前协程独占的连接上下文。如果没调 exec(),或中间抛异常跳出 try 块,连接就不会归还池子,直到协程结束(可能几分钟后)。
- 表现:连接数缓慢上涨、
SHOW PROCESSLIST出现大量Sleep状态连接、新请求持续报WaitTimeoutException - 定位方法:在 pipeline/multi 调用前后加日志,检查
Context::has($mysql->getContextKey())是否始终为 true - 修复方式:必须用 try/finally 包裹,确保
exec()或discard()执行;不要依赖 GC 或协程退出自动回收 - 注意:WebSocket 长连接、定时任务协程也容易漏掉归还,它们持有的连接不会随 HTTP 请求结束而释放
真正难调的从来不是某个参数,而是这几个值之间的咬合关系:wait_timeout 决定协程能等多久,max_idle_time 和 heartbeat 决定连接在池里能活多久,ATTR_TIMEOUT 决定连接干活时能忍多久,而 pipeline 归还不归还,直接决定连接能不能回到池里——漏掉任意一环,重连就只是纸上谈兵。



















