本质是连接未归还或max_idle_time未生效:默认为0(永不过期),仅对pdo/mysqli生效,redis需用pool.idle_timeout;须小于mysql wait_timeout(建议55~300秒),并确保连接在协程退出前正确归还。

Hyperf 中数据库连接不释放,本质不是“销毁慢”,而是连接没被归还或配置未生效。关键在 连接池空闲策略 和 协程上下文生命周期 两个层面。
检查并启用 max_idle_time
Hyperf 默认 max_idle_time = 0,即空闲连接永不过期——这是 Sleep 连接堆积的最常见原因。
- 该参数只对
hyperf/database的 pdo/mysqli 驱动生效,Redis 连接池需用pool.idle_timeout - 值应小于 MySQL 的
wait_timeout(默认 28800 秒),建议设为55.0~300.0秒 - 必须显式配置,不能依赖环境变量未定义时的默认值
确保连接被正确归还
连接未归还是比配置错误更隐蔽的问题:协程退出时若连接仍被持有,它会一直留在池中占用 slot,直到超时才被清理。
- 避免在
try块中调用$redis->multi()或$redis->pipeline()后未执行exec(),异常跳出会导致连接卡死 - 手动获取连接(如
DB::getConnection())后,不要长期持有;业务逻辑结束即退出作用域,让连接自动归还 - Eloquent 查询(如
User::query()->get())内部已自动复用和归还,无需干预
监控连接池真实使用率
靠猜不如看数。连接池是否健康,得看实时状态,而不是日志有没有报错。
- 用
PoolFactory::getPool('default')->getCurrentConnections()获取当前总连接数 - 用
getConnectionsInChannel()查空闲连接数,差值即为正在使用的连接 - 若
getCurrentConnections长期接近max_connections,说明池子真不够用,或存在泄漏 - 可结合
co::stats()和memory_get_usage(true)辅助判断是否有上下文残留
配合服务端限制做协同调优
Hyperf 的连接池再合理,也受限于数据库服务端能力。单边优化容易白忙。
- PostgreSQL 查
SHOW max_connections,Hyperf 的max_connections建议不超过其 70% - MySQL 查
SHOW VARIABLES LIKE 'max_connections',同时关注SHOW PROCESSLIST中idle in transaction连接 - 若发现大量
idle in transaction,说明事务未提交或回滚,要从代码查beginTransaction/commit/rollback是否配对











