max_user_connections 控制单用户并发连接上限,设为1时仅允许一个活跃会话,优先级高于全局配置;需配合调低wait_timeout及连接池参数防Sleep连接堆积;验证须用SHOW PROCESSLIST而非SHOW GRANTS。

max_user_connections 是控制“同一时间最多几个连接”的关键参数
它直接限制某个用户在任意时刻能建立的并发连接数,比如设为 1,就强制该用户只能保持一个活跃会话,第二个连接会被拒绝并报错 Too many connections(注意:不是全局 max_connections 的错误,而是账户级拒绝)。
这个值优先级高于全局 max_user_connections 系统变量——只要给用户显式设置了非零值,MySQL 就完全忽略全局配置,只认该用户的设定。
- 创建用户时直接指定:
CREATE USER 'api_user'@'%' WITH MAX_USER_CONNECTIONS 1; - 修改已有用户:
ALTER USER 'api_user'@'%' WITH MAX_USER_CONNECTIONS 1; - 查当前值:
SELECT user, host, max_user_connections FROM mysql.user WHERE user = 'api_user';(需有SELECT权限查系统表) - 设为
0表示不限制,但要注意:0是显式取消限制,不是“继承全局”
为什么只设 max_user_connections=1 还可能失败
常见现象是应用反复重连后仍出现多个连接,或者 SHOW PROCESSLIST 里看到同一个用户有两条以上记录。原因通常是:
- 应用未正确关闭连接(比如没调
conn.close()或连接池未配置回收策略),旧连接实际还活着,只是处于Sleep状态 - MySQL 的
wait_timeout默认是 28800 秒(8 小时),空闲连接不会立刻释放,所以即使用户只开一个连接,也可能因超时不生效而“堆积” - 连接池(如 HikariCP)自身维护连接生命周期,若配置了
maximumPoolSize > 1,它会无视数据库层限制主动建多个连接
解决办法是组合使用:MAX_USER_CONNECTIONS + 合理调低 wait_timeout(比如设为 300),并在连接池中启用 idle_timeout 和 max_lifetime,确保连接不长期滞留。
max_connections_per_hour 不等于“同时在线”,别混淆
MAX_CONNECTIONS_PER_HOUR 控制的是“每小时最多发起几次新连接”,和“当前有几个连接”无关。它防的是高频重连攻击,不是并发会话控制。
举例:设为 5,用户可以在第 1 分钟连 5 次,然后断开所有连接;第 2 分钟再连 5 次,依然合法。只要没超频次,哪怕只保留 1 个长连接,也不会触发限制。
- 适用场景:防止脚本暴力重试、爬虫频繁建连
- 不适用场景:强制单点登录、禁止多端同时操作
- 错误用法:
ALTER USER 'user'@'%' WITH MAX_CONNECTIONS_PER_HOUR 1;—— 这只会让第一次连接成功,之后一小时内无法再连,但已存在的连接照常工作
验证是否生效必须看 processlist 而非 show grants
SHOW GRANTS FOR 'user'@'%' 不会显示资源限制项,它只返回权限语句。真正生效的限制存于 mysql.user 表,且只有运行时才起作用。
最直接的验证方式是手动模拟并发连接:
- 开两个终端,都执行:
mysql -u user -p -h your-host - 如果第二个连接立即报错
ERROR 1226 (42000): User 'user' has exceeded the 'max_user_connections' resource (current value: 1),说明生效 - 再执行
SHOW PROCESSLIST;,确认该用户只有一条状态非Sleep的记录(或最多一条活跃+一条刚 idle 的) - 注意:root 用户不受此限制影响,测试务必用目标普通用户
容易被忽略的一点是:MySQL 对连接数的统计基于 user@host 全匹配。如果用户从不同 IP 登录(如 'user'@'192.168.1.10' 和 'user'@'192.168.1.11'),它们算两个独立账户,各自受自己的 max_user_connections 限制。


















