mysql 8.0+ 中 max_queries_per_hour 不生效,仅为兼容占位符;真正有效的仅 max_connections_per_hour,需用 grant usage 设置且只限制新连接次数。

用 ALTER USER 设置 MAX_QUERIES_PER_HOUR 真的有用吗?
在 MySQL 8.0+ 中,MAX_QUERIES_PER_HOUR 语法能执行成功,但**运行时不生效**——它不再触发限流逻辑,也不会报 ERROR 1226。MySQL 5.7.6+ 起默认跳过 mysql.user 表中 max_questions 字段的校验;8.0 彻底移除该字段的运行时检查。即使你执行了:ALTER USER 'api'@'%' WITH MAX_QUERIES_PER_HOUR 60;,后续连续执行 100 次 SELECT 1 也完全不会被拦截。
它现在只是个兼容性占位符,不是可用的限流机制。
那怎么真正限制每小时查询次数?
生产环境必须绕过 MySQL 原生限制,用中间件实现:
• ProxySQL 是目前最可行的选择:它支持按用户名 + 时间窗口统计 SQL 执行次数,且可精确到 SELECT、INSERT 等类型。
• 关键配置不是单条语句,而是组合:
– 插入规则匹配用户名和语句模式(如 ^SELECT )
– 启用 stats_mysql_query_digest 并配合外部脚本每小时清空或告警
– 或使用 ProxySQL v2.4+ 的 mysql_query_rules 新字段 + Lua 脚本做滑动窗口计数
• 不要用应用层 Redis 计数替代:它无法感知 MySQL 实际执行是否成功,且跨事务、重试、连接池场景下极易误判。
如何正确设置每小时最大连接数?
MAX_CONNECTIONS_PER_HOUR 是唯一仍在 MySQL 内核中有效运行的账户级时间窗口限制,但它只管「新连接建立次数」,不管查询多少次。
必须用 GRANT USAGE 设置,不能用 ALTER USER:GRANT USAGE ON *.* TO 'app'@'%' WITH MAX_CONNECTIONS_PER_HOUR 120;
然后立刻执行:FLUSH PRIVILEGES;
验证是否生效:SELECT User, Host, max_connections FROM mysql.user WHERE User = 'app';
注意:
• 它不统计连接池复用——HikariCP 开 10 个连接但每小时只连一次,就只算 1 次
• 若用户已存在且有其他权限,GRANT USAGE 不会覆盖已有授权,只追加限制
• 错误写成 CREATE USER ... WITH MAX_CONNECTIONS_PER_HOUR 且漏掉 WITH 关键字,会静默失败
为什么两个限制不能混用一个命令?
因为它们底层机制完全不同:
• MAX_QUERIES_PER_HOUR 在 8.0+ 已失效,语法保留但无逻辑支撑
• MAX_CONNECTIONS_PER_HOUR 仍由服务端实时校验,但仅对 mysql_real_connect() 成功认证计数
两者从不共享状态、不共用计数器、也不互相降级。你设了前者,等于没设;设了后者,只拦连接动作。
最容易被忽略的是:连接池让 MAX_CONNECTIONS_PER_HOUR 极难触发,而你以为的“查太多被拦”,实际根本没走这个路径——它压根没机会生效。











