Hyperf中MySQL连接“短链接化”实为连接池复用失败,主因是max_idle_time配置不当(须严格小于MySQL的wait_timeout且不宜过小)、手动获取连接后未释放、min_connections设为0或max_connections盲目调高。

为什么Hyperf里MySQL连接会“短链接化”
Hyperf本身用的是协程连接池,不是短链接;所谓“频繁创建”,其实是连接池配置失当或业务代码没释放连接,导致连接不断新建又丢弃。本质是连接复用失败,不是协议层的短链接(如PHP-FPM那种每次请求重建TCP)。常见现象包括:SHOW PROCESSLIST里大量Sleep状态连接不回收、Threads_connected持续上涨、日志中反复出现Connection reconnect failed。
检查max_idle_time和wait_timeout是否冲突
MySQL服务端有wait_timeout(默认28800秒),而Hyperf连接池的max_idle_time(默认60秒)若远小于它,就会出现连接在池里“睡着了”却被MySQL主动断开,下次取用时触发重连——表面看是频繁创建,实则是被动重建。
-
max_idle_time必须严格小于MySQL的wait_timeout,但不能过小(比如设成5秒),否则连接刚空闲就回收,失去复用意义 - 推荐值:MySQL侧
wait_timeout设为300–600,Hyperf侧max_idle_time设为30–45,留出安全缓冲 - 同时检查
pool.wait_timeout(获取连接的等待超时),避免协程卡在“等连接”上,建议设为5.0而非默认3.0
确认getConnection()调用后是否归还连接
Hyperf的DB::connection()->select(...)这类Eloquent/Query Builder操作会自动管理连接生命周期;但一旦你手动调用DB::getConnection()或$this->connection->getConnection(),就必须显式释放——否则连接永远滞留在协程上下文里,不会归还给池。
- 错误写法:
$conn = DB::getConnection(); $conn->query(...);→ 忘记Context::set($key, null)或未触发自动回收 - 正确做法:优先走Query Builder封装层;若必须手管连接,确保在
finally块中调用ConnectionInterface::close()或清空Context - 协程上下文泄漏比传统线程更隐蔽——一个协程不释放,整个连接就被独占,直到该协程结束
避免min_connections设为0或max_connections盲目调高
min_connections=0看似节省资源,实则高并发时所有连接都要动态创建,放大瞬时压力;而max_connections设得过大(如100+),既超出MySQL的max_connections限制,又让连接池无法及时感知数据库瓶颈,掩盖真实问题。
- 先查MySQL当前最大允许连接数:
SHOW VARIABLES LIKE 'max_connections'; - Hyperf的
pool.max_connections建议设为MySQL值的60%–70%,留出空间给后台任务、监控、运维连接 -
min_connections至少设为2–5,保证冷启动后有基础连接可用,避免首波请求全卡在建连上 - 真正要调的是
pool.max_idle_time和pool.max_connections的组合,而不是单点加码
连接池不是越大越好,也不是越“懒”越省事;关键在让连接在“够用”和“不过期”之间卡准那个时间窗口。很多问题其实不发生在SQL里,而藏在max_idle_time和MySQL wait_timeout那几十秒的错位里。



















