Workerman数据库连接池报错主因是配置与用法错误:Connection refused/timeout因在onWorkerStart中创建同步连接;Too many connections因池大小超MySQL上限;Query hangs因PDO同步调用混入协程;Pool empty因未正确复用池对象。

Workerman 4.0.34 中数据库连接池报错频发,多数源于连接未复用、池参数越界或同步调用混入协程——不是框架缺陷,而是配置与用法踩中了长驻进程的底层逻辑。
禁止在 onWorkerStart 中创建 PDO/MySQLi 同步连接
第一步:打开你的 Worker 启动文件(通常是 start.php 或 Events.php),搜索 onWorkerStart 回调函数内部是否出现 new PDO()、mysqli_connect() 或 Capsule::bootEloquent()。
第二步:若存在,立即删除。这些同步连接一旦建立,就会被该 Worker 进程长期持有,既不释放也不复用,高并发时直接触发 MySQL 的 max_connections 限制,后续请求全部卡在 Connection refused 或 timeout。
第三步:改用 Swoole\Coroutine\MySQL 封装的异步连接池,或 Workerman 官方推荐的 Workerman\MySQL\Connection 类——它默认启用协程兼容模式,所有 query() 返回 Promise,不阻塞 EventLoop。
注意:PDO::ATTR_PERSISTENT => true 在 onWorkerStart 中也必须禁用,持久连接在此场景下反而加速连接耗尽。
连接池最大数不能超 MySQL 全局上限
方法一:查 MySQL 实际限制
登录 MySQL 执行 SHOW VARIABLES LIKE 'max_connections';,记下返回值(如 200)。
方法二:按比例设置池大小
若你启用了 8 个 Worker 进程($worker->count = 8),每个连接池的 max_connections 建议设为 MySQL 总限制的 60% ÷ Worker 数,即 200 × 0.6 ÷ 8 ≈ 15;若只启 2 个 Worker,则可设为 60。
方法三:强制启用生命周期管理
在连接池配置中必须加入 'maxLifetime' => 1800000(30 分钟)、'idleTimeout' => 600000(10 分钟)。否则空闲连接可能被 MySQL 主动断开,而池子无法感知,下次取出即报 MySQL server has gone away。
协程中严禁直接调用 PDO::query()
如果你在 onMessage、onWorkerStart 以外的协程上下文(例如控制器方法、定时器回调、WebSocket 消息处理函数)里写了 $pdo->query('SELECT ...'),立刻停手。
这种写法会让当前协程彻底阻塞,CPU 占用不高但响应时间飙升,且同一 Worker 内其他请求全部排队等待——现象是“偶尔某次查询突然变慢”,实则是调度链被锁死。
验证方式:临时把所有 DB 查询替换成 go(function () { usleep(3000000); });,如果延迟依旧存在,说明问题根源就是协程被同步调用卡住。
正确做法:仅使用 Workerman\MySQL\Connection 实例的 query() 方法,或改用 mysql2(Node.js)等真正异步驱动——PHP 原生 PDO 不支持协程,硬上等于自废调度能力。
连接归还前必须重置状态
Workerman\MySQL\Connection 默认会在连接归还时执行 rollback() 并重置 autocommit 状态,但如果你自行封装了连接池或使用第三方包,请确认以下三点:
① 归还连接前是否显式调用了 $connection->rollback()(事务未提交时);
② 是否清除了上次查询残留的游标、临时表、用户变量;
③ 是否重置了字符集和时区设置——不同请求可能修改 session-level 配置,不重置会导致下一个使用者拿到污染的连接。
若跳过这一步,可能出现“前一个请求的 SET NAMES gbk 影响下一个 UTF8 查询”这类隐蔽乱码问题,排查成本极高。

















