webman数据库连接池报错主因是配置与用法错误:connection refused/timeout因在onworkerstart中创建同步连接;too many connections因池大小超mysql上限;query hangs因pdo同步调用混入协程;pool empty因未正确复用池对象。

Webman 数据库连接池报错,90% 是因为连接没复用、池子配错或同步阻塞混进协程环境——不是框架不行,是配置和用法踩了坑。
Connection refused 或 timeout 报错:先看是不是在 onWorkerStart 里 new MySQLi/PDO
Workerman 的 Worker 进程常驻内存,onWorkerStart 只执行一次。但很多人把 new PDO() 或 mysqli_connect() 写在这里,以为“只连一次”,结果每个 Worker 进程都持有一个长期空闲的同步连接,既不归还也不复用,高并发时直接触发 MySQL 的 max_connections 限制,后续请求全卡在 Connection refused 或超时。
- 必须改用异步 MySQL 客户端,如
Swoole\Coroutine\MySQL,配合连接池封装 - 禁止在
onWorkerStart中做任何阻塞式数据库初始化(包括PDO::ATTR_PERSISTENT => true) - 若用 Eloquent,确保
Capsule::bootEloquent()只调一次,且PDO::ATTR_PERSISTENT设为false
Too many connections 错误:连接池 max_connections 超过 MySQL 服务上限
连接池最大连接数不是越大越好。max_connections 配太高,所有 Worker 进程加起来会突破 MySQL 的 max_connections 全局限制(默认通常 151),导致新连接被拒绝,错误信息常为 SQLSTATE[HY000] [1040] Too many connections。
Webman 2.2.0版本强化了 TCP/UDP 服务支持,优化路由组管理,并增强异步任务处理能力。结合协程与连接池技术,Webman 能轻松应对高并发场景,适用于网站、接口服务、即时通讯、物联网及游戏开发,兼具高性能、灵活扩展与稳定可靠,是多场景 PHP 服务开发的理想选择。
- 查 MySQL 当前限制:
SHOW VARIABLES LIKE 'max_connections'; - Webman 连接池的
max_connections建议设为 MySQL 总限制的 60%~70%,例如 MySQL 是 200,则池子最多配 120~140 - 如果启用了多个 Worker 进程(
$worker->count = 12),每个池子的max_connections要按比例下调,避免总和超标 - 务必开启连接生命周期管理:
maxLifetime(建议 1800000ms)、idleTimeout(建议 600000ms)
Query hangs 或响应变长:PDO 同步调用混入协程上下文
Webman 支持协程,但原生 PDO 和 MySQLi 是同步阻塞的。一旦你在协程中(比如 onMessage 回调或控制器里)直接执行 $pdo->query(),整个协程会被卡住,无法让出控制权,看起来像“某次查询突然变慢”,实则是阻塞了整条协程调度链。
- 现象:单个慢查会让同一 Worker 内其他请求全部延迟,
top看 CPU 不高但响应时间飙升 - 验证方式:临时把所有 DB 查询换成
go(function () { sleep(3); });,如果问题依旧,说明不是 DB 层而是协程调度被阻塞 - 解决路径:要么彻底切换到
Swoole\Coroutine\MySQL+ 连接池,要么把同步查询扔进runInSeparateProcess()或异步任务队列 - 别信“PDO::ATTR_TIMEOUT”能救场——它只控制连接建立阶段,不解决 query 执行阻塞
Pool always empty:连接池对象没在协程内正确复用
常见错误是把连接池实例定义成全局变量或 static 属性,比如在 config/database.php 里 new Pool(),然后在控制器里直接调用。这会导致每次请求都尝试从同一个池对象取连接,但协程环境下没有锁保护,容易出现 Pool is empty 或死等。
- 正确做法:连接池对象应在每次协程入口(如路由回调、
onMessage)中获取,用完立即释放(->release()) - 推荐结构:
go(function () { $pool = \support\DbPool::instance(); $mysql = $pool->get(); try { $result = $mysql->query('SELECT ...'); } finally { $pool->put($mysql); } }); - 不要依赖构造函数自动回收——Swoole 协程结束不会自动触发析构,必须显式
put() - 检查是否误用了
yield或co::sleep()在未释放连接时挂起协程,导致连接被长期占用
最易被忽略的一点:连接池的 min_connections 设为 0 没问题,但如果你业务启动就高频访问 DB,冷启动时每次都要新建连接,会放大首次延迟;建议设为 2~5,让池子有基础水位。另外,所有连接池参数(max_connections、timeout、maxLifetime)必须在协程启动前完成初始化,晚于 go() 调用才生效的配置等于没配。










