从库上show processlist显示大量waiting for master to send event是i/o线程正常等待主库binlog的状态,非异常;真正风险在于应用层未正确管理连接池导致sleep连接堆积,引发max_connections耗尽。

主从复制中 SHOW PROCESSLIST 显示大量 Waiting for master to send event
这是从库 I/O 线程正常等待主库 binlog 的状态,不是连接泄漏,但容易误判为“长连接堆积”。真正的问题往往藏在应用层——比如应用直连从库时未正确复用连接,或连接池配置与复制延迟不匹配。
常见错误现象:SHOW PROCESSLIST 里出现大量 Sleep 状态的客户端连接(非复制线程),且 Time 值持续增长;Threads_connected 缓慢上涨,最终触发 max_connections 限制。
- 确认这些连接来源:查
Host列,若为应用服务器 IP,说明是应用连接池未释放,和复制本身无关 - 复制线程(
system user)的Time高是正常的,只要Seconds_Behind_Master稳定就不需干预 - 避免在从库上执行长事务或大查询,它们会阻塞复制线程获取 relay log 锁,间接拉长 I/O 线程等待时间
Java 应用连接从库时 maxIdle 和 minIdle 设太高导致空闲连接滞留
很多团队把连接池的 minIdle 设成 20+,以为能“预热”性能,结果从库上堆满 100+ Sleep 连接,还误以为是复制异常。
MySQL 服务端不会主动断开空闲连接,全靠客户端或中间件管理生命周期。JDBC 默认 wait_timeout=28800(8 小时),但应用连接池若不主动回收,连接就一直挂着。
-
minIdle建议设为 0 或 ≤5,尤其读多写少、流量波动大的从库场景 - 开启连接池的
testOnBorrow(慎用)或更推荐的testWhileIdle+timeBetweenEvictionRunsMillis,定期探测并清理失效连接 - 务必同步调整 MySQL 的
wait_timeout(建议 300–600 秒),否则连接池的空闲检测可能失效
ProxySQL 后接多个从库时,mysql_servers 表里的 max_connections 被忽略
ProxySQL 的 max_connections 字段只控制 ProxySQL 自身到后端 MySQL 的**单个连接数上限**,不是总连接池大小。实际并发由 mysql_query_rules 中的 apply 逻辑和 mysql_users 的 max_connections 共同决定。
典型翻车点:给从库组配了 max_connections=100,但 ProxySQL 实际打过去 300+ 连接,SHOW PROCESSLIST 里全是 Connect 状态,从库 Threads_connected 爆表。
- 真正生效的是
mysql_users.max_connections(用户级)和mysql_servers.weight(负载权重),前者限制该用户通过 ProxySQL 能建立的总连接数 - 检查
stats_mysql_connection_pool表,看ConnUsed和ConnFree是否持续高位,确认是否连接复用失败 - 如果从库实例较弱,别只调高
weight,要同步压低mysql_users.max_connections,避免流量倾斜压垮单节点
从库 read_only=1 下仍出现 Can't execute the given command because you have active locked tables
这个报错看似权限问题,实则是连接未显式关闭事务,又没提交/回滚,导致表锁残留。在 read_only=1 的从库上,任何写操作(包括隐式 DML 如 INSERT ... SELECT)都会被拒绝,但锁依然挂着。
后果比主库更隐蔽:锁不释放 → 后续 SELECT 可能被阻塞 → 连接卡住 → 连接池不断新建连接补位 → 连接数雪崩。
- 所有访问从库的代码必须确保:开启事务后,无论成功失败,都显式
COMMIT或ROLLBACK - 禁用 JDBC 的
autoCommit=false默认值,除非业务明确需要手动事务;对只读查询,保持autoCommit=true最安全 - 在从库上定期跑
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW()) - TIME_TO_SEC(TRX_STARTED) > 60,揪出长事务源头
连接池不是越大越好,从库资源比主库更敏感;真正危险的不是复制线程的“长等待”,而是应用层那些没人管的 Sleep 连接——它们不报错,只悄悄吃光 max_connections。











