audit_log插件不记录越权操作,因其仅在权限校验通过、语句进入执行阶段后才记录;权限拒绝等拦截行为发生在执行前,由error_log捕获,需结合log_error_verbosity=3与audit_log_format=JSON双日志时间对齐分析。

MySQL 8.0 默认不记录越权操作(如失败的 SELECT、INSERT 或权限拒绝事件),audit_log 插件只记录“成功执行”的语句,且对权限校验失败类行为静默忽略——必须靠组合配置+外部日志交叉验证才能捕获。
为什么 audit_log 查不到 “拒绝访问” 类越权行为
audit_log 插件的设计逻辑是:只在 SQL 解析器完成语法检查、权限系统放行、语句真正进入执行阶段后才记录。而越权操作(如用户 u1@% 尝试 SELECT FROM admin_table)在权限检查环节就被拦截,根本不会走到执行层,因此 audit_log 里完全空白。
- 典型现象:
SELECT * FROM mysql.audit_log或审计文件中查不到SELECT语句,但错误日志里有Access denied for user 'u1'@'%' to database 'admin_db' - audit_log 的
command_class字段只会出现select、insert等,但绝不会出现access_denied或类似标识 - MySQL 错误日志(
error_log)才是越权行为的第一落点,它记录所有权限拒绝、认证失败、语法错误等拦截事件
audit_log + error_log 双日志联动排查越权
单靠 audit_log 无法闭环追踪越权,必须把它的结构化 SQL 记录和 error_log 的拦截上下文对齐时间戳和用户来源。
- 确保
log_error_verbosity = 3(MySQL 8.0.22+),让 error_log 包含完整user_host和query上下文(如[Note] Access denied for user 'u1'@'10.0.1.5' using password: YES) - 开启 audit_log 时设
audit_log_policy = ALL,并确认audit_log_format = JSON,这样每条记录含user、host、timestamp、query字段,便于和 error_log 对齐 - 用时间窗口比对:比如 error_log 在
"2026-09-28T14:22:03"记录了拒绝事件,就查 audit_log 中前后 5 秒内是否有同user_host的其他操作(可能用户先试探了 GRANT 权限,再尝试越权查询) - 脚本示例(实时关联):
tail -f /var/log/mysql/error.log | grep -E "(Access denied|plugin.*failed)" & tail -f /var/log/mysql/audit.log | jq -r 'select(.user and .query) | "\(.timestamp) \(.user)@\(.host) \(.query)"'
server_audit 插件能补上部分越权缺口
相比官方 audit_log,server_audit(MariaDB 兼容版)在社区实践中更早支持记录权限拒绝事件,但需手动启用对应事件类型。
- 加载后必须显式开启:
SET GLOBAL server_audit_events = 'CONNECT,QUERY_DDL,QUERY_DML,TABLE,FAILED_LOGIN';—— 注意FAILED_LOGIN是关键,它会记录认证失败和权限拒绝 - 日志输出到文件时,
server_audit_output_type = file,每行格式为date,user,host,connection_id,operation,object,result,其中result字段为0(成功)或1(失败) - 常见失败 operation 值:
QUERY(SQL 执行被拒)、TABLE(表级权限不足)、CONNECT(登录失败) - 注意:
server_audit不记录被拒绝语句的完整query内容,只记操作类型和对象名(如admin_table),敏感度低于 audit_log,但覆盖场景更广
真正有效的越权监控要靠应用层埋点+数据库代理
纯 MySQL 层审计存在固有盲区:它看不到连接池复用后的实际业务用户、看不到 ORM 自动生成的隐式查询、也抓不住绕过 MySQL 协议直连存储引擎的行为。
- 如果业务用 Java + MyBatis,应在
Interceptor中记录userId、sql、dataSource,和 MySQL 的user_host关联;失败时主动上报越权事件到 ELK - 在数据库前加 Proxy(如 ProxySQL 或 MaxScale),它能拦截并记录所有客户端原始请求,包括被 MySQL 拒绝前的完整包,且可配置规则告警(如匹配
SELECT.*admin_且用户不在白名单) - audit_log 的
audit_log_include_accounts必须配全高危账户(如'dba@%', 'root@localhost', 'app_admin@10.0.%'),否则即使开了 ALL,插件也可能因账户未命中策略而跳过记录
越权操作的审计本质是“失败路径”的可观测性问题,MySQL 自身不提供开箱即用的解决方案。最易被忽略的是:很多人花大力气配好 audit_log 后,就以为万事大吉,却没打开 error_log 的详细级别,也没做双日志时间对齐——结果越权行为明明发生了,日志里却像什么都没发生过。


















