Hyperf 的 MySQL 连接不会自动销毁闲置连接,除非正确配置 max_idle_time(单位秒、须置于 pool 子数组下、建议 ≤ MySQL wait_timeout−30),且需配合 heartbeat 启用,销毁发生在下次 release() 时而非定时扫描。

Hyperf 的 MySQL 连接不会“自动销毁闲置连接”,除非你明确配置了 max_idle_time 并确保它生效——默认值是 0(永不过期),且只对 hyperf/database 的 PDO/MySQLi 驱动起作用。
为什么 max_idle_time 设了却没销毁连接
常见现象是:配置写了、服务也重启了,但 SHOW PROCESSLIST 里仍堆满 Sleep 状态连接。这不是 bug,而是以下几点没对齐:
-
max_idle_time必须放在'pool'子数组下,写在数据库配置顶层会静默失效 - 值单位是秒(不是毫秒),写成
60000就等于设成 16.7 小时,远超 MySQL 的wait_timeout - 若同时设了
min_connections(如2),空闲连接数不会低于该值,哪怕超时也不会被回收 - 连接真正销毁发生在下次
release()时,不是后台定时扫描——低流量场景下,“滞留”可能持续数分钟(Swoole 4.8+ 惰性回收机制)
正确配置 max_idle_time 的位置和写法
在 config/autoload/databases.php 中,针对 MySQL 数据库配置:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306'),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'strict' => true,
'options' => [
\PDO::ATTR_TIMEOUT => 3,
],
'pool' => [
'min_connections' => 2,
'max_connections' => 32,
'connect_timeout' => 5.0,
'wait_timeout' => 5.0,
'max_idle_time' => 30, // ✅ 单位:秒,必须 ≤ MySQL 的 wait_timeout - 30
],
],
关键细节:
-
max_idle_time值建议设为 MySQL 实际wait_timeout减去至少 30 秒(查法:SELECT @@wait_timeout;) -
min_connections别设 0,否则冷启延迟高;2是较稳妥的起点 -
connect_timeout建议从默认10.0降到5.0,避免网络抖动阻塞协程调度器
验证销毁是否真在发生
不能只看配置文件,得看运行时行为:
- 开启
hyperf/logger的DEBUG级别日志,搜索"Connection destroyed",确认有销毁日志周期性出现 - 用
swoole_timer_tick定期调用$pool->getStats(),观察idle_num是否随时间下降 - 在数据库端执行
SELECT ID, TIME, STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep';,检查连接存活时长是否趋近你设的max_idle_time
最容易被忽略的是:Swoole 后台空闲检查线程(IdleConnectionChecker)依赖 max_idle_time 和 heartbeat 协同工作——如果只配 max_idle_time 但没开 heartbeat,或 heartbeat 值大于 max_idle_time,销毁动作可能被跳过或延迟很久才触发。


















