audit_log插件默认不记录任何事件;必须显式配置audit_log_policy(如logins、all)才启用审计,且不支持按dml/ddl语句类型精细过滤,仅能按事件类型(如query)粗粒度控制,故“只记录dml+ddl”需依赖all策略+json日志后解析实现。

audit_log 插件默认记录什么,为什么不能直接“只开 DML+DDL”
MySQL 8.0.19+ 社区版自带的 audit_log 插件不支持按 SQL 类型(如 INSERT/UPDATE/CREATE)精细过滤;它只按事件类型(CONNECT、QUERY、TABLE_ACCESS 等)分类,而 QUERY 事件会包含所有语句(包括 SELECT、SET、SHOW),无法在插件层剔除 SELECT。所以“只记录 DML 与 DDL”在 audit_log 插件中本质是做不到的——它要么全开 QUERY(含所有语句),要么关掉(丢失 DML/DDL 上下文)。
用 audit_log_policy = 'ALL' + 日志后处理实现逻辑上的“只留 DML/DDL”
这是生产中最可行的折中方案:启用全量 QUERY 事件,再通过日志解析过滤出目标操作。需注意三点:
-
audit_log_policy必须设为'ALL'(不是'LOGINS'或'QUERIES'),否则 DDL(如CREATE TABLE)可能被归入TABLE_ACCESS而漏记 - 日志格式强烈推荐
audit_log_format = 'JSON',便于用jq或 Python 解析record["status"]和record["query"]字段 - 过滤逻辑示例(bash + jq):
jq -r 'select(.event == "QUERY" and (.query | test("^(INSERT|UPDATE|DELETE|REPLACE|CREATE|ALTER|DROP|TRUNCATE)", "i")))'注意:不能仅靠command字段,因为社区版audit_log的command值常为空或不准,必须依赖query字符串匹配
替代方案:binlog + mysqlbinlog 工具提取 DML/DDL
如果只要 DML/DDL 文本且不关心执行者/IP/时间戳精度,binlog 更轻量、原生支持、无性能额外开销。但要注意:
-
binlog_format必须为STATEMENT或MIXED,ROW格式不记录原始 SQL,只记录变更后的行数据 -
binlog不记录SELECT、SHOW、连接行为,天然符合“只 DML/DDL”需求 - 提取命令示例:
mysqlbinlog --base64-output=DECODE-ROWS --verbose /var/lib/mysql/mysql-bin.000001 | grep -E "^(INSERT|UPDATE|DELETE|CREATE|ALTER|DROP) "
实际使用建议加--start-datetime和--stop-datetime控制范围 - 权限要求:用户需有
REPLICATION CLIENT权限才能读取 binlog
为什么不要用 general_log
general_log 确实能记录所有语句文本,但它完全不区分用户、IP、执行结果状态码,且写入是同步阻塞式,高并发下 I/O 毛刺明显。生产环境开启后,QPS 下降 15–30% 很常见,还容易因磁盘满导致 MySQL 挂起。它只适合单次排查,不能作为审计日志长期运行。
真正要落地“只记录 DML/DDL”,核心矛盾在于:MySQL 社区版没有内置的、带 SQL 类型白名单的审计插件。要么接受 audit_log 的冗余再过滤,要么用 binlog 舍弃上下文换简洁性。选哪个,取决于你更看重谁执行了、从哪执行的(选前者),还是更看重语句本身是否可回放(选后者)。











