不是必须开 general_log,但它是直接“操作录像”;没开时 binlog(需 ROW 格式)是唯一能还原真实 SQL 的来源;云数据库需通过平台审计功能开启,且默认不启用、保留时间短。

MySQL 没开 general_log 就没法查谁删了数据?
不是必须开 general_log,但它是最直接的“操作录像”。没开的话,binlog 是唯一能还原真实 SQL 的来源——前提是开启了 binlog_format = ROW 且保留时间够长。general_log 记所有语句但性能损耗大,生产环境通常关着;binlog 默认只记逻辑变更(STATEMENT 格式),遇到 NOW()、UUID() 等函数就无法精确还原原始语句。
-
binlog必须启用:log_bin = ON,且binlog_format = ROW才能看见被删的每一行内容 -
SHOW VARIABLES LIKE 'log_bin';和SHOW VARIABLES LIKE 'binlog_format';先确认这两项 - 如果用的是
STATEMENT或MIXED,DELETE FROM t WHERE id=123能看到,但DELETE FROM t WHERE updated_at 只会记成“执行了一条 DELETE”,删了哪些行完全不可知
用 mysqlbinlog 解析出具体删除行为
mysqlbinlog 是唯一能从 binlog 文件里提取原始操作的命令。它不连接数据库,而是读取磁盘上的 .000001 类文件,所以得先找到对应时间段的 binlog 文件名。
- 查当前活跃 binlog:
SHOW MASTER LOGS;,再结合SHOW BINLOG EVENTS IN 'mysql-bin.000005' LIMIT 20;快速定位时间范围 - 导出可读 SQL:
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000005 > out.sql,注意必须加--base64-output=DECODE-ROWS -v,否则看不到 ROW 模式下的具体行数据 - 输出里找
### DELETE FROM `db`.`table`开头的块,每块下面的### @1=123就是被删行的主键值 - 别直接在生产库上运行
mysqlbinlog—— 它会读锁 binlog 文件,高并发下可能卡住写入
PostgreSQL 怎么查谁删了数据?
PostgreSQL 没有内置类似 MySQL 的 row-level binlog,审计靠扩展或日志配置。最可靠的是开启 pg_audit 扩展,其次才是解析 CSV 格式的 log_statement = 'all' 日志——但后者只记语句模板,不记参数值,DELETE 语句里的 WHERE 条件全变成问号。
- 启用
pg_audit需要:安装扩展、shared_preload_libraries = 'pgaudit'、重启、CREATE EXTENSION pgaudit; - 设审计级别:
SET pgaudit.log = 'write';(含 INSERT/UPDATE/DELETE)或更细粒度如SET pgaudit.log_relation = on; - 日志输出位置由
log_destination决定,常见是csvlog,得用log_line_prefix = '%m [%p] %q%u@%d '才能对齐时间戳和用户 - 没装
pg_audit时,log_statement = 'ddl'或'mod'只能告诉你“有人执行了 DELETE”,但不知道删了哪几行
云数据库(RDS/Aurora/Cloud SQL)能不能看操作日志?
能,但权限和路径和自建库完全不同。云厂商把审计日志收归平台侧,不让你直接读磁盘文件,也不开放 mysqlbinlog 工具。你得去控制台翻“SQL 审计日志”开关,而且默认关闭、按量计费、有保留天数限制。
- AWS RDS MySQL:必须创建带
aurora-mysql-advanced-audit参数组的实例,再开启audit_log_policy = ALL,日志推送到 CloudWatch Logs - 阿里云 RDS:开通“SQL 审计”功能(非免费),日志存 OSS,支持按库、表、用户筛选,但不记录
binlog级别行变更 - Google Cloud SQL:只提供慢日志和错误日志,审计需搭配
cloudsql.enable_sqlserver_audit(仅 SQL Server)或用Log Export+Filter抓DELETE关键字,精度有限 - 关键提醒:云上日志不是“随时可查”,很多服务默认保留 7 天,等你发现数据丢了再开,早就没用了
查删库删表这种事,真正难的从来不是“怎么查”,而是“日志有没有开、开得够不够细、留得够不够久”。等报错才想起翻日志,大概率只剩一条 ERROR 1049 (42000): Unknown database 在那里冷笑。

















