audit_log插件在mysql 8.0.19+社区版中已原生内置但默认不加载,需先验证版本及插件可用性,再通过my.cnf配置plugin_load_add、audit_log=force_plus_permanent、audit_log_format=json并重启服务,运行时执行set global audit_log_policy='all'启用全量审计,且audit_log_file路径须在配置文件中指定绝对路径并确保mysql用户可写、selinux放行,否则必然静默失效。

audit_log 插件在 MySQL 8.0.19+ 社区版中已原生内置,但默认不加载、不启用。不装插件、不配 audit_log_policy、不设 audit_log_file 路径权限,日志就等于没开——不是“可能不写”,是“必然静默失效”。
确认版本与插件可用性再动手
低于 8.0.19 的社区版没有 audit_log.so,硬执行 INSTALL PLUGIN 会报 ERROR 1126 (HY000): Can't open shared library 'audit_log.so'。
必须先验证:
-
SELECT VERSION();—— 确保返回类似8.0.33或更高 -
SHOW VARIABLES LIKE 'have_audit_log';—— 返回YES表示编译时启用了支持 -
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'audit_log';—— 有结果且状态为ACTIVE或DISABLED才可继续;若无返回,说明插件文件缺失或未加载
加载插件并持久化配置(重启不失效)
INSTALL PLUGIN 只是运行时加载,MySQL 重启后插件自动卸载。要真正“开起来”,必须把关键参数写进 my.cnf 并重启服务。
- 在
[mysqld]段添加三行(顺序无关,但缺一不可):plugin_load_add = audit_log.so<br>audit_log = FORCE_PLUS_PERMANENT<br>audit_log_format = JSON
-
audit_log = FORCE_PLUS_PERMANENT是关键:它让插件强制加载且禁止被UNINSTALL,否则运维误操作或脚本清理可能意外关闭审计 -
audit_log_format = JSON必须显式指定——默认是NEWLINE,字段无标识、IP 和 SQL 内容藏在固定列里,解析困难且易漏失败登录 - 改完配置后必须
systemctl restart mysqld,FLUSH PRIVILEGES或SET GLOBAL都不生效
设置 audit_log_policy 和日志路径
audit_log_policy 是运行时开关,决定记录什么事件类型;而 audit_log_file 路径必须在配置文件里写死,运行时修改无效。
- 连接 MySQL 后执行:
SET GLOBAL audit_log_policy = 'ALL';(可选值仅ALL、LOGINS、QUERIES;VALIDATE会直接报错) - 在
my.cnf的[mysqld]段加:audit_log_file = /var/log/mysql/audit.log—— 必须是绝对路径,不能含变量、空格、中文或软链接 - 确保目录可写:
sudo mkdir -p /var/log/mysql && sudo chown mysql:mysql /var/log/mysql && sudo chmod 755 /var/log/mysql - SELinux 默认拦截:
sudo setsebool -P mysqld_read_default_logs on,否则日志文件创建失败且无报错提示
验证是否真在记录 + 常见静默失败点
日志文件存在但为空?或有内容但查不到登录行为?大概率卡在这几个地方:
-
audit_log_policy没设 —— 插件加载了,但策略是默认关闭状态,日志就是空的 - Unix socket 登录(如
mysql -u root不带-h)不会被记录,audit_log只捕获 TCP/IP 连接,这是设计限制,不是配置问题 - 日志里看不到完整 SQL?因为
audit_log默认只记录元数据(用户、IP、时间、命令类型、状态码),不记录SELECT语句文本;DDL/DML 的query字段只在部分事件中出现,且可能被截断(受audit_log_read_buffer_size限制,默认 1M,建议调至 4M) - 高并发下 JSON 日志体积比 NEWLINE 大 30%~50%,不设
audit_log_rotate_on_size = 10000000(10MB)容易撑满磁盘——插件自身不轮转,靠这个参数触发归档
JSON 格式日志每行是一个独立对象,不能直接 cat audit.log | jq .,要用 jq -r '. | select(.name == "connect")' audit.log 或逐行解析。最常被忽略的是:路径权限、SELinux、socket 登录盲区、以及误以为它能记录所有 SQL 文本——它记录的是“谁在何时做了什么动作”,不是“每条 SQL 的完整快照”。











