Hyperf连接池空闲连接不释放的典型表现是服务运行后数据库Sleep连接持续堆积,根本原因是max_idle_time默认为0(永不过期)且仅对hyperf/database的pdo/mysqli生效,redis连接池需用pool.idle_timeout而非max_idle_time。

Hyperf连接池空闲连接不释放?max_idle_time没生效的典型表现
常见现象是:服务运行一段时间后,数据库连接数持续上涨、SHOW PROCESSLIST里大量Sleep状态连接堆积,但业务无明显并发增长。这通常不是max_idle_time设得不够长,而是它根本没被正确启用——Hyperf默认使用max_idle_time = 0(即永不过期),且该配置只对部分连接池驱动生效。
max_idle_time在不同连接池中的实际作用范围
这个参数是否起效,取决于你用的是哪个连接池组件:
-
hyperf/database(基于hyperf/pool):支持max_idle_time,但仅对pdo和mysqli有效;redis连接池(hyperf/redis)**不识别该配置**,需改用pool.idle_timeout -
hyperf/redis:必须通过pool.idle_timeout控制空闲超时,max_idle_time会被忽略 -
hyperf/http-client:使用pool.max_idle_time,注意命名多一个pool.前缀
混淆这些配置名是导致“设了没用”的最常见原因。
正确配置max_idle_time的实操要点
以hyperf/database为例,在config/autoload/databases.php中设置:
'mysql' => [
'driver' => 'mysql',
'pool' => [
'max_idle_time' => 60, // 单位:秒,不是毫秒
],
// 其他配置...
],
关键细节:
- 值单位是**秒**,不是毫秒(和Swoole原生
max_idle_time一致,但容易误写成60000) - 必须放在
pool子数组下,写在顶层会静默失效 - 若同时设置了
min_connections,空闲连接数不会低于该值,即使超时也不会被回收 - 连接真正释放发生在下次
release时,不是定时扫描清理——这意味着低流量场景下,空闲连接可能“滞留”更久
验证空闲连接是否按预期关闭
不能只看配置文件有没有写对,要观测运行时行为:
- 开启
hyperf/logger的DEBUG级别日志,搜索"Connection released"和"Connection destroyed",确认销毁日志出现频率与max_idle_time匹配 - 用
swoole_timer_tick定期调用$pool->getStats(),检查idle_num是否随时间下降 - 数据库端执行
SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep',观察连接存活时长是否趋近你设的max_idle_time
最容易被忽略的是:Swoole 4.8+ 对max_idle_time做了优化,默认启用惰性回收,如果连接池长期无新请求,空闲连接可能延迟数分钟才真正释放——这不是bug,是设计使然。











