mysql 5.7+ 开启 general_log 捕获 ddl 需执行 set global general_log = on 且 log_output = 'file',日志中用 grep 提取 create/drop/alter 等语句,但不记录失败操作。

MySQL 5.7+ 如何开启 general_log 捕获 DDL 语句
general_log 能记录所有客户端发送的 SQL,包括 CREATE、DROP、ALTER 等 DDL,但默认关闭,且日志格式不区分用户/时间戳细节,容易淹没在大量查询中。
实操建议:
- 只在临时审计期开启,避免磁盘暴增:
SET GLOBAL general_log = ON,日志路径由general_log_file控制(默认/var/lib/mysql/hostname.log) - 必须配合
log_output = 'FILE'(不能是'TABLE',否则mysql.general_log表无法记录自身结构变更) - DDL 语句在日志里是纯文本,需用
grep -E '^(CREATE|DROP|ALTER|RENAME)' /var/lib/mysql/hostname.log提取,注意匹配大小写和空格位置 - 不记录执行失败的 DDL(比如权限不足报错
ERROR 1142 (42000): ALTER command denied不会进日志)
MySQL 8.0 audit_log 插件是否真能审计 DDL
官方 audit_log 插件(需企业版或 MySQL 8.0.25+ 社区版启用)支持 AUDIT_LOG_FILTER,但默认只记录连接、查询、退出事件,DDL 属于 QUERY 类型,需显式过滤。
实操建议:
- 加载插件后,创建过滤器:
CREATE AUDIT LOG FILTER my_ddl_filter WITH SCHEMA audit_log_filter_simple WHERE event_name IN ('statement/sql/create_db', 'statement/sql/drop_db', 'statement/sql/alter_db', 'statement/sql/create_table', 'statement/sql/drop_table', 'statement/sql/alter_table') - 注意事件名严格区分大小写和下划线,漏掉
statement/sql/rename_table就捕获不到RENAME TABLE - 日志输出为 JSON,默认写入
/var/lib/mysql/audit.log,但字段不含执行用户 host,仅含user(如"user": "admin@%"),无法区分同名用户不同来源 - 插件启用后,每个 DDL 都会触发一次磁盘写入,高频 DDL 场景下 I/O 压力明显,不建议长期开启
用 INFORMATION_SCHEMA + binlog 解析补全 DDL 审计链路
单纯依赖日志有盲区:general_log 可能被清空,audit_log 不记录失败操作,而 binlog 记录的是最终生效的 DDL(含 GTID),但需解析才能读出语句。
实操建议:
- 确认 binlog_format =
STATEMENT或MIXED(ROW格式下 DDL 仍以 statement 形式记录,但 DML 不可见) - 用
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000001查看,搜索# at后紧跟的CREATE/ALTER行,注意时间戳在 preceding#行 - 结合
INFORMATION_SCHEMA.TABLES或COLUMNS的UPDATE_TIME字段做交叉验证:某表UPDATE_TIME突然更新,但 general_log 无对应ALTER TABLE,大概率是应用直连改了结构没走统一入口 - binlog 中的 DDL 语句可能被重写(如添加默认数据库名),实际执行语句需对照 client 发送原始内容比对
为什么 trigger + sys schema 不适合做 DDL 审计
有人想用 CREATE TRIGGER 监听 information_schema 变更,或查 sys.schema_table_statistics_with_buffer,这条路走不通。
原因很直接:
-
INFORMATION_SCHEMA是只读视图,无法对其建 trigger -
sys库下的统计表(如schema_table_statistics)只反映 DML 频次,DDL 不更新这些计数器 - MySQL 不允许对
mysql系统库表(如mysql.tables)建 trigger,会报错ERROR 1356 (HY000): View 'mysql.tables' references invalid table(s) or column(s) - 哪怕绕过限制用外部轮询(如定时查
TABLES.CREATE_TIME),也无法获取操作者、SQL 原文、执行上下文(事务/autocommit 状态)
DDL 审计真正难的不是“记下来”,而是把语句、人、时间、结果(成功/失败)、上下文这五要素串成一条可追溯的链。每个方案都只覆盖其中两三个点,得根据你的 MySQL 版本、运维权限、存储成本和响应时效要求,选最痛的那个缺口先堵上。











