空闲连接本身无害,但空闲+权限+可复用构成隐患;需通过SHOW PROCESSLIST筛查长期Sleep连接、用Performance Schema捕获越权SQL、配置HikariCP初始化SQL重置会话,并严格限制监控账号权限。

怎么确认连接池里有没有被恶意复用或未授权的空闲连接
连接池本身不校验“谁用了连接”,只管借还;所谓“非法访问”往往不是黑客直连,而是应用内代码误用(比如线程A拿了连接,没关,线程B又从池里拿到同一个物理连接继续用),或者监控用户权限配置过宽导致敏感操作逃逸。真正要防的,是连接被错误复用、越权执行、长期空闲却仍持有着权限上下文。
-
SHOW PROCESSLIST是第一道筛子:重点关注Command为Sleep但Time超过 300 秒的连接,尤其User是应用账号而非 DBA,且db字段非空——这说明连接已空闲很久,但依然挂着某个业务库权限,存在被劫持风险 - 必须限制监控账号权限:创建
exporter用户时,绝不能给SUPER或ALL PRIVILEGES,只要PROCESS、REPLICATION CLIENT和SELECT ON performance_schema.*就够了;否则攻击者一旦拿下该账号,就能通过performance_schema.threads看到所有线程的原始 SQL 和用户上下文 - HikariCP 的
leakDetectionThreshold设为 60000(毫秒)后,若某连接超时未归还,它会在日志里打出带堆栈的警告,但不会自动 kill 连接——你得配合 AOP 或日志告警系统主动拦截,否则只是“知道漏了”,不是“堵住了”
如何用 Performance Schema 捕获非法连接行为
MySQL 原生的 performance_schema 可以记录每个连接的完整生命周期事件,包括谁在什么时间点执行了哪条语句、是否持有锁、是否等待 I/O——这才是判断“非法”的技术依据,而不是靠 IP 黑白名单这种外围手段。
- 启用关键采集器:
UPDATE performance_schema.setup_instruments SET ENABLED='YES' WHERE NAME LIKE 'statement/%' OR NAME LIKE 'wait/io/file/innodb%';,否则查不到 SQL 级别行为 - 查异常连接行为:
SELECT THREAD_ID, USER, HOST, EVENT_NAME, TIMER_WAIT FROM performance_schema.events_statements_history_long WHERE SQL_TEXT LIKE '%DROP TABLE%' AND USER != 'admin_user';—— 这类语句本不该由普通应用账号执行,一旦命中就是越权信号 - 注意
events_statements_history_long默认只保留 10000 行,高并发下容易被覆盖;如需长期审计,得搭配slow_query_log+log_output = TABLE写入mysql.slow_log表,并定期归档
为什么空闲连接本身不是问题,但空闲+权限+可复用才是隐患
连接池维持空闲连接是为了性能,这是合理设计;问题出在“空闲连接仍保有完整会话状态”,比如当前数据库(db)、临时表、用户变量、事务隔离级别、甚至已持有的元数据锁——这些状态不会因空闲而清空,下次被借走时直接继承,极易引发跨请求污染。
- 检查连接复用痕迹:
SELECT ID, USER, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 60;,如果DB字段固定为某个业务库,说明该连接始终绑定着那个库上下文,不是“干净”的空闲 - HikariCP 的
connection-init-sql配置项可以写USE mysql; SET @app_id = NULL;,每次借出前重置会话环境,但不能执行DROP TEMPORARY TABLE类语句,因为连接可能还没建临时表就先执行了初始化 SQL,会报错 - InnoDB 层面的
innodb_lock_wait_timeout和连接空闲无关,但若一个空闲连接曾开启事务却未提交,它持有的行锁会一直挂着——这时看performance_schema.data_locks才能发现真实阻塞源
监控配置里最容易被忽略的权限与超时组合
很多人配完 mysqld_exporter 就以为万事大吉,其实它的配置文件 .my.cnf 里一行权限疏漏,或一个超时参数设错,就会让整个连接池安全监控形同虚设。
-
[client]段落里如果漏了host = localhost,mysqld_exporter可能走 TCP 连接而非 socket,触发 SELinux 或防火墙拦截,导致指标中断数小时都无告警 -
wait_timeout和interactive_timeout必须小于连接池的idleTimeout(HikariCP 默认 10 分钟),否则 MySQL 主动断开连接,而池子还认为连接有效,下次借出时抛Communications link failure异常 - 用
sys.schema_table_statistics_with_buffer视图查表级 I/O 时,如果performance_schema里setup_consumers没开events_statements_history,这个视图就返回空——不是没数据,是根本没采
PROCESSLIST、performance_schema 和连接池日志三者对齐看。


















