mysql默认不记录用户登录行为,必须启用audit_log插件才能审计非法访问;它可记录连接失败事件(如status:1045)、用户/ip、时间戳等,而general_log仅记录已认证会话的sql,完全漏掉登录失败环节。

MySQL 默认不开启通用查询日志(general_log),且它记录所有语句(包括合法登录),无法直接区分“非法访问尝试”。真正能用于审计暴力破解或异常登录行为的是 error_log(错误日志)和 slow_log(慢查询日志)以外的更关键来源:MySQL 8.0+ 的 audit_log 插件,或系统层的认证失败记录(如 /var/log/secure 或 journald)。单纯靠 SELECT 查询通用日志基本无效。
为什么不能依赖 general_log 审计非法访问
general_log 只在连接建立成功后才记录语句,而非法访问尝试(如密码错误、用户不存在)根本不会进入该日志——它们连会话都没创建成功。你看到的全是已认证用户的操作,完全漏掉了最关键的失败环节。
- 开启方式:
SET GLOBAL general_log = ON;,但对审计登录失败无意义 - 日志内容示例:
Connect root@localhost on test using TCP/IP—— 这行只出现在登录成功时 - 性能代价高:每条 SQL 都写磁盘,生产环境严禁长期开启
真正有效的审计入口是 MySQL 错误日志 + 系统认证日志
MySQL 自身的错误日志(由 log_error 配置项指定路径)会记录明确的认证失败事件,格式为:[Warning] Access denied for user 'xxx'@'yyy' (using password: YES/NO)。这是最直接的非法访问证据。
- 确认错误日志位置:
SELECT @@log_error;,常见路径如/var/log/mysql/error.log或/var/lib/mysql/hostname.err - 快速提取失败账号:
grep "Access denied" /var/log/mysql/error.log | awk -F"'" '{print $2,$4}' | sort | uniq -c | sort -nr - 注意时区:MySQL 错误日志时间默认用系统本地时区,与
SELECT NOW()可能不一致,比对需换算 - 如果启用了
log_warnings = 2(MySQL 5.7+ 默认),失败登录会额外记录客户端 IP 和错误码(如ER_ACCESS_DENIED_ERROR)
MySQL 8.0+ 推荐启用 audit_log 插件做细粒度控制
原生 audit_log 插件可记录连接/断开事件,包括失败尝试,且支持 JSON 格式、按用户/IP 过滤,比错误日志更结构化。
- 检查是否加载:
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME = 'audit_log'; - 启用后默认记录所有连接事件,失败登录会带
"status":1045(对应ER_ACCESS_DENIED_ERROR) - 关键配置项:
audit_log_policy = ALL(记录所有事件),audit_log_format = JSON(方便解析) - 日志文件本身不可直接
SELECT查询,需用外部工具(如jq)解析:jq -r 'select(.status == 1045) | .account.user' /var/lib/mysql/audit.json - 注意权限:插件需要
SUPER或AUDIT_ADMIN权限,且日志文件属主必须是mysql用户,否则启动失败
最常被忽略的一点:MySQL 错误日志里 “Access denied” 行可能被轮转覆盖,且默认不记录失败次数的时间窗口。如果要实时拦截暴力破解,光看日志不够,必须配合 fail2ban 规则监听 /var/log/mysql/error.log 或系统 /var/log/secure,并自动封禁 IP。审计只是第一步,响应动作得靠外部系统补全。











