wait_timeout 是 MySQL 最重要的连接超时参数,控制空闲连接在服务器端保持打开状态的最大时长。合理配置能有效防止连接泄漏和资源耗尽。


一、核心作用

作用对象 :非交互式客户端的空闲连接(Sleep 状态的线程)

触发行为 :当一个连接在 wait_timeout 秒内没有任何活动(查询),MySQL 将 主动断开该连接

关键区别

  • 只针对 空闲状态,不影响正在执行查询的连接

  • 与应用层超时无关:客户端可能仍认为连接有效,但服务器已关闭


二、参数详解

默认值

  • MySQL 5.7/8.0 : wait_timeout = 28800 8 小时!)

双生参数:interactive_timeout

# 交互式客户端(如 mysql 命令行)的空闲超时
interactive_timeout = 28800

# 非交互式客户端(JDBC/PHP/Python等应用)的空闲超时
wait_timeout = 28800

生效规则 :

  • 连接建立时,服务器根据客户端类型 二选一设置

  • 大多数应用驱动属于 非交互式 ,受 wait_timeout 控制


三、配置方法

1. 动态调整(立即生效,重启失效)

-- 全局生效(需 SUPER 权限)
SET GLOBAL wait_timeout = 600;

-- 当前会话生效(测试用)
SET SESSION wait_timeout = 600;

2. 永久配置

[mysqld]
# 推荐值:10-30 分钟
wait_timeout = 600
interactive_timeout = 600

# 可针对特定用户设置(MySQL 8.0+)
# CREATE USER 'app_user'@'%' WITH MAX_CONNECTIONS_PER_HOUR 100;

重启生效

sudo systemctl restart mysqld

四、最佳实践(⚠️ 现代应用必读)

核心原则:必须短于应用/代理超时

# 场景 1:使用连接池(HikariCP/SQLAlchemy)
[mysqld]
# 比连接池的 idleTimeout 稍长
wait_timeout = 300  # 5 分钟

# 场景 2:无连接池(强烈不推荐!)
[mysqld]
# 保守设置,避免频繁重连
wait_timeout = 1800  # 30 分钟

推荐配置示例

[mysqld]
# 必须配置
wait_timeout = 600
interactive_timeout = 600

# 关联配置:减少连接开销
thread_cache_size = 50

# 防止应用超时设置不当
net_read_timeout = 30
net_write_timeout = 60

与常见组件的配套

组件

推荐 wait_timeout

说明

HikariCP

300

idleTimeout (默认 600s) 稍短

Nginx

600

proxy_timeout

AWS RDS Proxy

300

匹配代理的空闲超时

PHP-FPM

180

匹配进程生命周期


五、常见问题与排查

问题 1:"MySQL server has gone away"

原因:应用持有一个超时已被服务器断开的连接,再次使用时报错。

排查

-- 查看当前空闲连接
SHOW PROCESSLIST;
-- 重点关注 Time 列 > wait_timeout 的线程

解决方案

  1. 应用层 :启用连接池并配置健康检查

  2. 紧急 :调高 wait_timeout(治标不治本)

  3. 代码层 :捕获异常并重试连接

问题 2:连接数居高不下

-- 统计各状态的连接数
SELECT COMMAND, COUNT(*) 
FROM INFORMATION_SCHEMA.PROCESSLIST 
GROUP BY COMMAND;

-- 常见结果:大量 Sleep 连接
+---------+----------+
| COMMAND | COUNT(*) |
+---------+----------+
| Sleep   | 150      |
| Query   | 5        |
+---------+----------+

处理方法

-- 手动清理长时间空闲连接(谨慎!)
SELECT CONCAT('KILL ',id,';') FROM INFORMATION_SCHEMA.PROCESSLIST 
WHERE COMMAND = 'Sleep' AND TIME > 600;

-- 生成 KILL 语句后执行

问题 3:修改不生效

-- 检查实际生效的值(区分全局和会话)
SHOW GLOBAL VARIABLES LIKE 'wait_timeout';
SHOW VARIABLES LIKE 'wait_timeout';  -- 当前会话

原因:客户端连接建立时会全局值到会话级,需 重新连接才生效。


六、与连接池的协同

现代应用架构

┌─────────────┐
│ 应用服务器   │
│ HikariCP    │  ← 配置 idleTimeout = 250s
└──────┬──────┘
       │ 复用连接
┌──────▼──────┐
│ MySQL Server│  ← wait_timeout = 300s
└─────────────┘

设计原则 :

  • 连接池超时 < wait_timeout

  • 允许服务器端稍晚清理,作为 兜底 防护

  • 应用层应主动管理连接生命周期


七、性能影响评估

高值的风险 (如默认 28800)

  • 资源泄漏 :应用忘记关闭连接导致 Threads_connected 持续上升

  • OOM 风险 :每个连接占用内存,5000 个空闲连接可能消耗数 GB

  • 文件句柄耗尽 :每个连接一个 socket

低值的风险 (如 < 30 秒)

  • 频繁重连开销 :TCP 握手 + 认证 + SSL 协商

  • 应用延迟 :连接池需要频繁创建新连接


八、总结与决策树

配置决策流程

是否使用连接池? → 是 → wait_timeout = 300
                ↓
                否 → 立即引入连接池!
                ↓
                (临时方案:wait_timeout = 1800)

核心记忆点

  1. 默认 8 小时是历史包袱,必须缩短

  2. 必须短于应用和代理的超时设置

  3. Sleep 连接 ≠ 无害,持续消耗资源

  4. 终极方案是连接池 + 合理 wait_timeout

推荐基准生产环境设置为 600(10 分钟) 是平衡资源与稳定性的起点。