一、连接超时是个什么鬼?

大家有没有遇到过这种情况:你在MySQL客户端里敲了半天SQL,突然想去接杯水,回来发现连接断开了?或者你的应用程序半夜跑着跑着就报"Lost connection to MySQL server"的错误?这很可能就是连接超时在作怪。

MySQL服务器不会无限期地保持空闲连接,它有两个重要的超时参数来控制这种行为:

  • wait_timeout:非交互式连接的超时时间(比如JDBC连接)
  • interactive_timeout:交互式连接的超时时间(比如MySQL命令行客户端)

这两个参数的单位都是秒,默认值通常是28800秒(8小时)。但实际生产环境中,这个默认值往往需要调整。

二、wait_timeout详解

wait_timeout控制的是非交互式连接的空闲超时时间。举个例子,你的Java应用通过连接池获取MySQL连接,如果这个连接空闲超过wait_timeout设置的时间,服务器就会主动断开它。

// Java示例:通过JDBC获取连接
try (Connection conn = DriverManager.getConnection(
        "jdbc:mysql://localhost:3306/mydb?user=root&password=123456")) {
    // 假设这里执行完查询后,连接被放回连接池
    Statement stmt = conn.createStatement();
    ResultSet rs = stmt.executeQuery("SELECT * FROM users");
    // ...处理结果集
} catch (SQLException e) {
    // 如果连接因为超时被断开,这里可能会捕获到异常
    e.printStackTrace();
}

这里有个坑:如果连接池不知道连接已经被服务器断开,下次从池中取出这个连接使用时就会报错。所以好的连接池(比如HikariCP)都会有连接健康检查机制。

三、interactive_timeout详解

interactive_timeout针对的是交互式连接,比如你用mysql命令行客户端连接服务器:

# 连接到MySQL服务器
mysql -u root -p

# 连接成功后,可以查看当前的interactive_timeout值
SHOW VARIABLES LIKE 'interactive_timeout';

假设interactive_timeout设置为1800秒(30分钟),如果你在命令行里30分钟不执行任何操作,下次执行命令时可能会看到: "ERROR 2006 (HY000): MySQL server has gone away"

这个参数对DBA特别重要,因为他们经常需要长时间保持连接但又不执行查询。

四、如何设置这些参数

设置方法有多种,我们来看最常用的几种:

  1. 配置文件my.cnf中设置(永久生效):
[mysqld]
wait_timeout = 600
interactive_timeout = 1800
  1. 动态设置(立即生效,但重启后会失效):
-- 设置全局值(影响之后新建的连接)
SET GLOBAL wait_timeout = 600;
SET GLOBAL interactive_timeout = 1800;

-- 设置当前会话的值
SET SESSION wait_timeout = 600;
  1. 启动时通过命令行参数设置:
mysqld --wait_timeout=600 --interactive_timeout=1800

五、实际应用中的注意事项

  1. 连接池配置要与超时设置匹配:
// HikariCP配置示例
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("root");
config.setPassword("123456");
// 设置连接最大空闲时间略小于wait_timeout
config.setIdleTimeout(500000); // 500秒,比wait_timeout的600秒小
  1. 长事务会阻止连接超时: 即使连接空闲,如果有未提交的事务,连接也不会被断开。

  2. 监控超时连接:

-- 查看当前所有连接及其状态
SHOW PROCESSLIST;

六、为什么需要调整默认值

默认的28800秒(8小时)在很多场景下不合适:

  1. 对于Web应用,通常几分钟不用的连接就可以回收了
  2. 保持过多空闲连接会浪费服务器资源
  3. 连接泄漏时,太长的超时会导致问题迟迟不能暴露

但也不能设得太短:

  1. 避免频繁重建连接的开销
  2. 考虑慢查询和批处理的执行时间
  3. 考虑应用可能的不活跃时段(如夜间)

七、常见问题排查

当出现连接断开问题时,可以这样排查:

  1. 检查当前设置:
SHOW VARIABLES LIKE '%timeout%';
  1. 检查连接最后活跃时间:
SELECT * FROM performance_schema.threads 
WHERE PROCESSLIST_COMMAND != 'Sleep';
  1. 检查错误日志:
# MySQL错误日志通常记录连接断开信息
[Note] Aborted connection 12345 to db: 'mydb' user: 'root' host: '10.0.0.1'
(Timeout)

八、最佳实践建议

  1. 生产环境建议设置:
  • wait_timeout: 300-600秒(5-10分钟)
  • interactive_timeout: 1800-3600秒(30-60分钟)
  1. 应用层配合:
  • 使用连接池并配置合理的验证查询
  • 对于长时间不用的连接,主动关闭
  • 实现连接重试逻辑
  1. 监控:
  • 监控连接数变化
  • 监控连接断开事件
  • 设置告警当异常断开增多时

记住,没有放之四海而皆准的配置,要根据你的具体应用特点来调整。