MySQL长连接内存溢出典型表现为大量Sleep连接长期存在、InnoDB缓冲池页数缓慢上涨、mysqld进程RSS内存持续增长,主因是未清理临时表、用户变量和预处理语句等会话资源。

MySQL长连接内存溢出的典型表现
不是所有“内存涨得快”都该怪长连接,但如果你观察到:SHOW PROCESSLIST 里大量 Sleep 状态连接持续数小时、innodb_buffer_pool_pages_total 缓慢上涨且不释放、OS 层 mysqld 进程 RSS 内存持续增长(尤其在无大查询时),那很可能是长连接携带未清理的会话状态(如临时表、用户变量、预处理语句缓存)导致的累积性内存泄漏。
这类问题在 Java 应用使用 HikariCP + MySQL Connector/J 且未配置合理连接回收策略时尤为常见——连接没断,但内部 @_session_state 类资源没清,MySQL 不主动释放。
wait_timeout 和 interactive_timeout 的实际作用边界
这两个参数只控制“空闲连接”的自动断开时机,不负责清理已分配但未释放的内存资源。它们生效前提是连接处于 Sleep 状态且超时,而一旦连接被应用层长期复用(比如框架 keep-alive 或连接池未启用 validate-query),就根本不会进入可被 timeout 清理的状态。
-
wait_timeout:对非交互式连接(如 JDBC 默认)生效,默认 28800 秒(8 小时) -
interactive_timeout:仅对启用了CLIENT_INTERACTIVE标志的连接(如 mysql CLI 加--interactive)生效 - 修改后需注意:应用层必须能容忍连接被服务端主动
KILL,否则会抛Communications link failure或Connection reset
建议值:生产环境设为 300(5 分钟),配合连接池的 maxLifetime 和 idleTimeout 错开 1–2 分钟,避免雪崩式重连。
连接重置前必须清理的三类会话资源
MySQL 不会在连接断开时自动清空所有会话级对象,尤其当连接被异常中断或 KILL 时。以下资源若长期堆积,会直接占用 thread_stack 和 sort_buffer_size 等线程级内存:
- 临时表(
CREATE TEMPORARY TABLE):即使连接 Sleep,只要没显式DROP或连接断开,就一直占内存+磁盘 - 用户变量(
@var := ...):生命周期绑定连接,但大对象(如@blob := LOAD_FILE('/huge'))不会被自动释放 - 预处理语句(
PREPARE stmt FROM ...):每个PREPARE占用数百字节内存,不DEALLOCATE PREPARE就一直留着
实操建议:
- 在连接归还池前,执行
RESET QUERY CACHE(已弃用,忽略)、DROP TEMPORARY TABLE IF EXISTS ...(需业务层记录)、SET @var = NULL(批量可写脚本) - 使用
mysql_reset_connection()(MySQL 5.7.3+ / Connector/J 8.0.14+):它比COM_RESET_CONNECTION更彻底,会清空会话变量、临时表、会话级系统变量,但不重置字符集和 SQL_MODE(这些需显式 SET)
验证连接是否真正“轻量”再复用
别只看 SHOW PROCESSLIST 的 Time 列,要查真实内存占用:
- 查当前连接的临时表:
SELECT * FROM information_schema.INNODB_TEMP_TABLE_INFO;
- 查会话变量大小(粗略):
SELECT VARIABLE_NAME, LENGTH(VARIABLE_VALUE) AS len FROM performance_schema.session_variables WHERE VARIABLE_NAME LIKE '@%' AND VARIABLE_VALUE IS NOT NULL ORDER BY len DESC LIMIT 5;
- 查预处理语句数量:
SELECT * FROM performance_schema.prepared_statements_instances WHERE OWNER_THREAD_ID IN (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_COMMAND = 'Sleep');
如果发现某类连接的 INNODB_TEMP_TABLE_INFO 行数稳定增长,或 prepared_statements_instances 中存在存活超 10 分钟的语句,说明应用层没有正确调用 DEALLOCATE PREPARE 或连接复用逻辑有缺陷。
连接池本身不是万能解药;它只是把问题从“频繁建连”转移到“长期持连”,而真正的内存控制点,在于每次归还前是否做了干净重置。


















