mysql 8.0+中grant select on mysql.*对slow_log无效,因该表属敏感系统元数据,通配符授权不覆盖,必须显式执行grant select on mysql.slow_log;且log_output需设为table并用set persist固化,否则重启失效。

MySQL 8.0+ 中 GRANT SELECT ON mysql.* 为什么对 slow_log 无效
这不是权限漏配,而是 MySQL 8.0 引入的显式系统表访问控制机制。即使你执行了 GRANT SELECT ON mysql.* TO 'user'@'%';,对 mysql.slow_log、mysql.general_log 等日志表仍会报错:ERROR 1142 (42000): SELECT command denied to user 'user'@'%' for table 'slow_log'。这是设计行为,不是 bug。
根本原因是:这些表被标记为“敏感系统元数据”,通配符授权不覆盖它们。必须显式指定全名——mysql.slow_log,且仅限 SELECT(该表只读,INSERT/UPDATE/DELETE 本身就被禁止)。
授予 slow_log 表只读权限的最小化操作
需分两步:先确保日志已启用并输出到表,再授予权限。
- 确认已启用表输出模式:
SET GLOBAL log_output = 'TABLE'; SET GLOBAL slow_query_log = ON;(若未启用,mysql.slow_log表为空或不存在) - 创建专用账号(如
logstash),避免复用 root:CREATE USER 'logstash'@'%' IDENTIFIED BY 'strong_password'; - 显式授予 SELECT:
GRANT SELECT ON mysql.slow_log TO 'logstash'@'%'; - Logstash 初始化时还会执行
SHOW VARIABLES和SELECT VERSION(),所以还需:GRANT USAGE ON *.* TO 'logstash'@'%';(注意:不是GRANT SELECT ON *.*,后者可能越权读取业务库) - 刷新权限:
FLUSH PRIVILEGES;
如果要用 FILE 方式读日志,FILE 权限不是给用户,而是给 MySQL 进程
FILE 是服务器级权限(Super_priv 相关),不能通过 GRANT 授予普通用户——它控制的是 MySQL 服务进程能否读写本地文件系统,与客户端账号无关。ELK 采集器若想直接读取 slow_query.log 文件,靠的是操作系统层面的文件权限(如 chown mysql:logstash /var/log/mysql/mysql-slow.log & chmod 640),而不是 MySQL 的 SQL 权限。
换句话说:GRANT FILE ON *.* TO 'user'@'%' 在现代 MySQL 中已被废弃,执行会报错或静默忽略。不要尝试。
Logstash JDBC Input 配置中容易踩的坑
即使权限和表都就绪,Logstash 仍可能拉不到新记录,常见原因:
-
jdbc_connection_string必须带时区参数,例如:jdbc:mysql://host:3306/?serverTimezone=UTC;否则start_time字段解析可能偏移,导致重复或漏读 - 增量查询语句里,
:sql_last_value必须是字符串格式的 DATETIME,如WHERE start_time > :sql_last_value,且 Logstash 需配置use_column_value => true和tracking_column => "start_time";传 Unix 时间戳会直接失败 -
mysql.slow_log表引擎是 CSV(8.0.22+ 改为CSV或PERFORMANCE_SCHEMA兼容引擎),不支持索引,大表查询慢;建议配合WHERE start_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)做时间范围裁剪
最易忽略的一点:MySQL 8.0 默认关闭 log_output = 'TABLE',且该设置无法通过 my.cnf 持久化(必须运行时 SET GLOBAL),服务重启后自动回退到 FILE,slow_log 表即失效——务必用 SET PERSIST log_output = 'TABLE'; 固化。











