mysql默认不记录grant等权限操作,需主动启用performance_schema的statement/abstract/account_management仪器及events_statements_history_long消费者,再查询该表中非dba账户执行的含super/replication/file等高危关键词的grant语句,并结合mysql.user表比对权限漂移。

MySQL 默认不记录 GRANT、CREATE USER 这类操作,所以“谁悄悄提权了”不会自动出现在日志里。必须主动启用 performance_schema 的账户管理事件采集,否则根本看不到痕迹。
确认 performance_schema 是否已启用并配置 account_management 仪器
很多环境默认开了 performance_schema,但关键的账户管理事件仪器是关闭的——这会导致 events_statements_history_long 里压根没有 GRANT 记录。
- 先查是否启用:
SELECT VARIABLE_VALUE FROM performance_schema.global_variables WHERE VARIABLE_NAME = 'performance_schema'—— 必须返回ON - 再查仪器状态:
SELECT ENABLED, TIMED FROM performance_schema.setup_instruments WHERE NAME = 'statement/abstract/account_management'—— 若为NO,需执行UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'statement/abstract/account_management' - 注意:仅开仪器不够,还要确保消费者开启,特别是
events_statements_history_long(不是只开events_statements_current)
查 events_statements_history_long 中非 DBA 账户的 GRANT 行为
权限异常提升往往不报错,只是某条 GRANT 语句静默执行成功。重点不是“有没有 GRANT”,而是“谁对谁授了什么权”。
- 过滤高危目标:
SQL_TEXT LIKE 'GRANT%SUPER%'、SQL_TEXT LIKE 'GRANT%REPLICATION%'、SQL_TEXT LIKE 'GRANT%FILE%' - 检查执行者身份:
USER和HOST是否匹配预期(例如'app_rw'@'10.20.30.%'执行了GRANT ALL ON *.*就极可疑) - 时间戳单位是纳秒:
TIMER_START > UNIX_TIMESTAMP(NOW() - INTERVAL 1 HOUR) * 1000000000,别直接用NOW()比较
结合 mysql.user 表比对权限漂移
单看一条 GRANT 语句还不够,得确认该账号当前实际拥有的权限是否与其历史行为或角色定位严重偏离。
- 查当前全局权限:
SELECT User, Host, Super_priv, Repl_client_priv, File_priv FROM mysql.user WHERE User != 'root' - 对比最近一次权限变更时间(如果启用了
last_used):SELECT User, Host, last_used FROM mysql.user WHERE last_used IS NULL OR last_used —— 突然活跃且权限飙升要警惕 - 特别注意
Grant_priv = 'Y'的普通账号:它能给自己或别人再授权,是横向扩散的关键跳板
真正难的是把 performance_schema 里的零散事件和业务上下文串起来——比如某条 GRANT 出现在 CI/CD 发布窗口之后,或紧随某个运维工单 ID 的注释,否则你只能看到“有人提权了”,却不知道为什么、是不是合法。这一步没法靠 SQL 自动完成,得靠人盯住变更链路。











