最常用方法是执行 set global general_log = on,立即生效且无需重启,可快速排查sql是否发出或被拦截,但需确认log_output为file、路径有写权限,并及时关闭以防磁盘写满。

怎么用 SQL 动态开启 general_log(最常用)
直接连上 MySQL,执行 SET GLOBAL general_log = ON 就能立刻生效,不用重启服务。这是排查连接异常、SQL 没执行到预期逻辑时最快的方式——比如你刚发了 SELECT * FROM users 却没返回结果,开日志一眼就能确认客户端到底发了什么、有没有被中间件改写或拦截。
但要注意三点:
-
general_log默认是OFF,且它记录的是「所有」事件:包括SHOW PROCESSLIST、PING、连接/断开、认证失败,甚至心跳包 - 必须先确保
log_output是FILE(默认值),否则日志可能写进mysql.general_log表里,而这张表引擎是CSV,查起来慢、导出难、还不能加索引 - 执行后立刻用
SHOW VARIABLES LIKE 'general_log%'确认状态和路径,避免写到不可写的目录(比如/root/下)导致静默失败
为什么 set global general_log_file 不生效?
常见现象是执行了 SET GLOBAL general_log_file = '/var/log/mysql/general.log',但日志还是写在旧路径,或者压根没生成文件。根本原因通常是权限或路径问题:
- MySQL 进程用户(通常是
mysql)对目标目录没有写权限——比如路径存在,但属主是root,就得提前chown mysql:mysql /var/log/mysql - 路径中父目录不存在(
general_log_file不会自动创建多级目录),得手动mkdir -p /var/log/mysql - 如果启用了
apparmor或selinux(尤其 Ubuntu/CentOS),可能拦截写入,临时关掉测试:sudo aa-disable /usr/sbin/mysqld或setenforce 0
永久开启要改 my.cnf,但配置不生效怎么办?
在 [mysqld] 段落下加这两行:
general_log = ON general_log_file = /var/log/mysql/general.log
重启后仍不生效,大概率是 MySQL 没读到这个配置文件。用这条命令查真实加载路径:
mysqld --help --verbose | grep "Default options"
常见坑有:
- Linux 上可能读的是
/etc/mysql/my.cnf而不是/etc/my.cnf;Docker 容器里常是/etc/mysql/conf.d/xxx.cnf - Windows 上是
C:\ProgramData\MySQL\MySQL Server 5.7\my.ini,注意路径里有空格,要用双引号包裹路径值 - MySQL 5.7+ 不再支持旧式
log = xxx写法,必须用general_log,拼错字母(比如general_logg)也不会报错,只会忽略
日志写满磁盘或性能暴跌,怎么收场?
general_log 不是监控工具,是调试放大镜。QPS 200+ 的库一开,磁盘写延迟常跳高 3–5 倍,部分慢查询反而被海量日志 I/O 掩盖。生产环境长期开着等于自废武功。
真要审计,优先考虑:
- 连接行为看
error log(含认证失败、拒绝连接) - 低效 SQL 用
slow_query_log+long_query_time = 0.1(只记超 100ms 的) - 全量操作审计走
binlog,配合init_connect记录登录用户(虽然不记 IP,但比 general_log 轻量得多)
如果等保要求必须开,务必配外部轮转——logrotate 每天切一次,或用定时脚本 echo > /var/log/mysql/general.log 清空(注意清空前先 FLUSH LOGS 防止残留句柄占用空间)。











