连接数过高本身不直接导致慢,真正拖垮响应的是“大量空闲连接堆积 + 少量活跃查询排队”组合——它同时耗尽内存、加剧锁竞争、抬高上下文切换开销;Threads_connected接近max_connections但Threads_running很低是典型假性过载,盲目调大max_connections反而恶化性能。

连接数过高本身不直接导致慢,真正拖垮响应的是“大量空闲连接堆积 + 少量活跃查询排队”这个组合——它同时吃光内存、加剧锁竞争、抬高上下文切换开销。
Threads_connected接近max_connections但Threads_running很低?这是典型假性过载
很多运维第一反应是调大 max_connections,结果越调越慢。因为:
-
Threads_connected高 ≠ 真在干活,SHOW PROCESSLIST里一堆State = 'Sleep'的连接,只是占着线程和内存不释放 - 每个连接默认吃掉 256KB–1MB 内存(含会话缓冲区、排序区、临时表空间),1000 连接 ≈ 多占 256MB–1GB 常驻内存
- OS 线程数暴涨后,
context switch次数常突破 5000/秒,CPU 大量时间花在调度上,而非执行 SQL
wait_timeout设太大,等于给僵尸连接发长期饭卡
MySQL 默认 wait_timeout = 28800(8 小时),而大多数应用空闲连接 30 秒内就该回收。后果很直接:
- 应用层没关连接 → MySQL 不主动断 → 连接挂着变 Sleep →
Time字段一路涨到几万秒 - 这些连接仍占用线程栈、会话变量内存、甚至可能持有表级锁(MyISAM)或事务锁(InnoDB)
- 新请求进来时,不是没连接可用,而是要排队等锁、等 CPU 调度、等内存分配 —— 表现就是响应延迟陡增,TPS 下跌
盲目启用thread_pool插件反而加重排队
MySQL 8.0+ 的 thread_pool 插件不是自动加速器,它只做连接层复用,不感知 SQL 执行耗时:
- 如果已有 200 个 Sleep 连接 + 50 个慢查询卡在队列里,新请求进来照样得等
-
thread_pool_size设太高(比如 32 核配 64),会导致线程争抢 mutex,innodb_row_lock_waits反而上升 - 必须配合
thread_pool_stall_limit(默认 600ms)防卡死,但设太小会误杀正常复杂查询
应用连接池maximumPoolSize > MySQL max_connections 是隐形炸弹
这是最常被忽略的硬冲突点:
- HikariCP 的
maximumPoolSize = 50,但 5 个微服务实例一齐启动 → 理论最大连接需求 = 250 - 若 MySQL
max_connections = 200,且没设admin_port,爆满时连管理员都 ssh 不进去 - 更糟的是:连接池等待超时(
connection-timeout)设成 30 秒,而 MySQLwait_timeout = 28800,池子会不断新建连接去填坑,形成恶性循环
真正关键的不是“有多少连接”,而是“谁在用、用了多久、用完放没放”。SHOW PROCESSLIST 和 Threads_running 的差值,比 max_connections 数值重要十倍。


















