
audit_log_format 设置成 STATEMENT 还是 JSON?
MySQL 审计日志的 audit_log_format 只支持两个值:NEWLINE(已弃用)、JSON,没有 STATEMENT 选项。官方文档里写的 “STATEMENT” 是旧版 MySQL Enterprise Audit 插件的遗留描述,5.7.28+ 和 8.0.x 中实际只认 JSON —— 设成其他值会导致插件加载失败或日志静默丢弃。
实操建议:
- 必须设为
JSON,否则audit_log插件可能无法启用,启动时会报错Plugin 'audit_log' init function returned error - 配置方式是:在 my.cnf 的
[mysqld]段下写audit_log_format=JSON,不能带引号、空格或注释 - 改完后要重启 mysqld;在线 SET 不生效,该变量是只读的(
read_only)
audit_log_policy=ALL 不等于“记录所有语句”
很多人以为设了 audit_log_policy=ALL 就能抓到每个 SELECT 或 INSERT,其实它只控制“审计事件类型”的粒度,比如连接、断开、查询开始/结束、表访问等,不控制 SQL 语句体是否写入日志。真正决定语句内容是否落盘的是 audit_log_include_accounts 和 audit_log_exclude_accounts 的匹配逻辑,以及用户权限(如是否拥有 AUDIT_ADMIN)。
常见错误现象:
- 日志里只有
connect/disconnect事件,没看到query类型 —— 很可能是账号被audit_log_exclude_accounts匹配到了 - root 用户有日志,普通用户没有 —— 检查该用户是否被显式排除,或是否缺少
AUDIT_ADMIN权限(部分版本要求) -
audit_log_policy=ALL下仍漏日志 —— 实际上 MySQL 默认只对具备SUPER或AUDIT_ADMIN的会话开启完整事件捕获,普通用户默认只记 connect/disconnect
audit_log_file 路径写错会导致插件静默失效
audit_log_file 不是普通日志路径,它受 MySQL 启动用户权限和 secure_file_priv 限制。设成 /var/log/mysql/audit.log 看似合理,但如果 mysqld 是以 mysql 用户运行,而该目录属主是 root 且无写权限,插件不会报错,而是直接放弃写日志 —— 表现为“配置全对,但文件始终为空”。
实操建议:
- 路径必须由 mysqld 进程用户可写,推荐用
/var/lib/mysql/audit.log(和数据目录同级,权限通常一致) - 不要跨挂载点(比如 NFS 或 tmpfs),某些系统调用(如
open(O_APPEND))在非本地文件系统上行为异常 - 确认
audit_log=ON已启用,且插件状态为ACTIVE(查SELECT * FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'audit_log')
JSON 格式日志解析慢?别直接用 grep
审计日志是行存 JSON(每行一个 JSON 对象),不是标准 JSON 数组,所以 jq '.event' 会失败。直接用 grep 查 "query" 字段容易误匹配字段名或字符串值,比如把 "user": "query_admin" 当成查询事件。
性能与可用性要点:
- 用
jq -r 'select(.event == "query") | .query' audit.log才能准确提取 SQL 内容 - 大日志文件(>1GB)用
jq会吃光内存,建议先用head/tail切片,或用awk '/"event":"query"/ {print; getline; print}'快速过滤 - MySQL 8.0.33+ 支持
audit_log_read表(需启用audit_log_reader插件),比解析文件更稳定,但该表只暴露元信息,不包含原始 SQL(出于安全限制)
最常被忽略的一点:JSON 日志里的 query 字段是经过 MySQL 内部脱敏处理的,WHERE 条件中的字符串字面量会被替换成 ?,不是原始 SQL —— 这不是配置问题,是设计如此。











