mysql 8.0.19+ 社区版需手动安装 audit_log 插件并设 audit_log_policy=all 或 logins,日志中通过 command_class:"grant"/"revoke" 字段识别权限变更,推荐用 jq 或 grep 实时过滤,注意 max_allowed_packet 大小及敏感信息管控。

MySQL 8.0+ 怎么开启审计日志捕获 GRANT 和 REVOKE
MySQL 自身不提供开箱即用的“权限变更审计”功能,audit_log 插件是唯一能原生记录 GRANT、REVOKE 等语句的方案,但它只在企业版默认可用;社区版需手动编译或换用替代方案。
实操上,优先确认你用的是 MySQL 8.0.19+ 社区版,并已安装 audit_log 插件(路径通常为 lib/plugin/audit_log.so)。没装就别硬配——它不会自动出现。
- 检查是否加载:
SHOW PLUGINS;查找audit_log行,状态必须是ACTIVE - 若未加载,运行:
INSTALL PLUGIN audit_log SONAME 'audit_log.so'; - 关键配置项:
audit_log_policy必须设为ALL或LOGINS(SYSTEM不记录GRANT) - 生效后,
GRANT SELECT ON db.* TO 'u'@'%';这类操作会在审计日志文件里留下"command_class":"grant"字段
audit_log 输出内容里怎么快速定位权限变更事件
审计日志是 JSON 格式,但默认不分行、不缩进,直接 tail -f 看非常反人类。真正有用的字段就三个:user、command_class、query。
常见错误是以为 audit_log_format=NEW 就能看懂日志——其实它只是让每条记录占一行,内容仍是紧凑 JSON。不解析根本没法 grep。
- 推荐实时过滤命令:
tail -f /var/lib/mysql/localhost.localdomain.json | jq 'select(.command_class == "grant" or .command_class == "revoke")' - 注意:
jq需要系统已安装;没有的话,先用grep -E '"command_class":"(grant|revoke)"'粗筛 -
query字段里可能含敏感信息(如明文密码),生产环境开启前得评估日志存储权限和访问控制 - 日志轮转靠
audit_log_rotate_on_size控制,别设太大,否则单个文件超百 MB 后jq解析会卡住
MySQL 5.7 或没权限装插件时,还能不能追踪 GRANT
不能依赖 audit_log,就得退到二进制日志(binlog)层面——但这里有个硬伤:GRANT 在 binlog 中默认不记 SQL 原文,只记对 mysql.user 等系统表的 DML 操作。
这意味着你看到的可能是 UPDATE mysql.user SET ...,而不是原始的 GRANT SELECT ON db.* TO 'u'@'%'。可读性差,还容易误判。
- 前提:确保
binlog_format = ROW(STATEMENT下完全不记录权限变更) - 用
mysqlbinlog --base64-output=DECODE-ROWS -v解析,搜索mysql.user、mysql.db、mysql.tables_priv相关更新 - 风险点:如果管理员执行了
FLUSH PRIVILEGES,或者直接INSERT INTO mysql.user,这些也会被记入,但不属于标准GRANT流程,容易混淆 - 性能影响:
ROW格式 + 系统表频繁更新,可能轻微增加binlog体积,不过权限表写入本身极少,实际压力不大
为什么 max_allowed_packet 会影响 audit_log 写入失败
审计日志插件内部把整条 JSON 记录当做一个“包”发给日志文件,如果某次 GRANT 涉及大量权限(比如给用户授 200 张表的 SELECT),生成的 JSON 可能超默认 max_allowed_packet(通常是 4MB)。
现象是:日志文件突然停止追加,SHOW VARIABLES LIKE 'audit_log%' 看起来正常,但新 GRANT 就是不记录——查错误日志会发现 Audit log: write failed: Packet too large。
- 临时修复:
SET GLOBAL max_allowed_packet = 8*1024*1024;(8MB) - 永久修复:在
my.cnf的[mysqld]段落加max_allowed_packet = 8M - 别设太高(如 1G),避免内存浪费;也别只调插件参数而忽略全局值,因为插件复用 MySQL 协议栈
- 这个坑只在高权限粒度场景下暴露,日常小规模授权几乎遇不到
真正麻烦的不是怎么开日志,而是日志里混着合法运维操作和可疑提权行为,没上下文很难判断哪条 GRANT 是异常的。建议至少关联记录操作者 IP 和时间戳,再喂给轻量级 SIEM 工具做规则匹配——纯靠人工盯日志,三天就放弃。











