mysql 8.0+ 不支持用户级 cpu/内存硬限额,仅能通过 resource group(仅限 select、需显式绑定)和 max_*_per_hour 类频次限制实现软性管控,真正资源隔离须依赖外部手段如 cgroups 或代理层限流。

MySQL 8.0+ 怎么给用户配 CPU 和内存限额
MySQL 原生不支持按用户限制 CPU 使用率或内存占用,所谓“限流”在 MySQL 里实际指 RESOURCE GROUP(资源组)配合线程绑定,或更现实的 MAX_QUERIES_PER_HOUR / MAX_UPDATES_PER_HOUR 这类语句频次控制。真想压住一个用户的内存/并发杀伤力,得靠组合策略。
-
RESOURCE GROUP只在 MySQL 8.0.19+ 支持,且仅对SELECT类只读查询生效,INSERT/UPDATE/DELETE不受控 - 必须用
SET RESOURCE GROUP显式绑定会话,用户自己不执行这句就无效;默认所有连接走USR_default组,没做任何限制 -
MAX_CONNECTIONS_PER_HOUR是最常用、最可靠的硬门槛,但只管“连多少次”,不管单次查询多耗资源 - 内存层面完全没用户级开关——
sort_buffer_size、join_buffer_size等都是会话级变量,用户登录后可自行SET调大,除非你禁掉SET权限(但会影响正常应用)
如何用 MAX_*_PER_HOUR 防住高频小查询刷崩服务器
这类限制适合防自动化脚本、爬虫或误写的轮询逻辑,不是为防大查询,而是卡住请求密度。它生效快、配置简单,但容易被绕过——比如把 100 次单行 SELECT 合成一条 IN 查询,次数就变成 1。
- 建用户时直接指定:
CREATE USER 'api_user'@'%' WITH MAX_QUERIES_PER_HOUR 300 MAX_UPDATES_PER_HOUR 50; - 已有用户用
ALTER USER修改:ALTER USER 'report_user'@'localhost' WITH MAX_CONNECTIONS_PER_HOUR 10; - 注意:这些值是“每小时累计”,不是滑动窗口;超限后该用户后续所有语句都会报错
ERROR 1226 (42000): User 'xxx' has exceeded the 'max_questions' resource - 如果应用用了连接池,
MAX_CONNECTIONS_PER_HOUR更有用——它限制的是mysql_real_connect()调用次数,不是活跃连接数
为什么不要依赖 old_password 或 GRANT 的旧式限流语法
MySQL 5.7 及以前支持在 GRANT 语句末尾写 WITH MAX_QUERIES_PER_HOUR 100,但这种写法在 8.0+ 已废弃,且存在严重歧义:它只对当前 GRANT 语句中列出的权限生效,没列的权限不受限——极易漏配,查问题时根本想不到。
- 新版必须用
ALTER USER ... WITH统一管理,和权限解耦 - 旧语法下,如果用户有多个
GRANT记录,取的是“最大值”,不是累加,调试时数值对不上 -
SHOW GRANTS FOR 'u'@'h'输出里不再显示这些限制项,得查mysql.user表的max_questions字段,字段名还和语法不一致(MAX_QUERIES_PER_HOUR对应max_questions),容易看串
真正压住资源消耗,还得靠外部手段兜底
MySQL 用户级机制本质是“礼貌性限速”,不是隔离墙。生产环境要防住恶意或失控查询,光靠它远远不够。
- 用
pt-kill定期杀长事务或高Rows_examined查询,比等它跑满一小时再报错更及时 - 在代理层(如 ProxySQL、MaxScale)设 query rules,按用户匹配 SQL 模式并限流,还能做滑动窗口计数
- Linux cgroups v2 + systemd scope 是最硬的手段:把 mysqld 的某个子进程(按 user 或 client ip 区分)绑到独立 memory/cpu controller 下,但运维成本高,需 DBA 和 infra 协同
- 别忘了检查
innodb_buffer_pool_size和tmp_table_size这些全局设置——它们才是影响整体内存水位的关键,用户级参数只是毛毛雨
用户级资源控制像自行车锁,能防顺手牵羊,但真有人拿液压剪来,得靠墙、监控和响应流程拦住。细节全在 mysql.user 表字段含义、RESOURCE GROUP 的适用范围,还有——别信文档里没写清楚兼容性的那几行小字。










