read_only=ON 不能阻止 root 用户写入,因其仅限制普通用户,SUPER 权限用户(如 root)仍可执行写操作;需回收 SUPER 权限或启用 super_read_only=ON 才能真正限制。

read_only=ON 为什么不能阻止 root 用户写入
MySQL 的 read_only 参数只对普通用户生效,root(或拥有 SUPER 权限的用户)仍可执行写操作。这是设计使然,不是 bug。
常见错误现象:SET GLOBAL read_only = ON; 后用 root 账号照样能 INSERT、UPDATE,误以为配置失败。
- 必须回收 root 或高权限用户的
SUPER权限才能真正限制:REVOKE SUPER ON *.* FROM 'root'@'%'; - 生产环境建议创建专用只读账号,并显式授予
SELECT权限,而非依赖read_only单一控制 -
read_only不影响临时表(CREATE TEMPORARY TABLE)、日志表(如mysql.general_log)等系统级操作
my.cnf 中设置 read_only 后不生效的典型原因
修改配置文件后重启 MySQL,但 SELECT @@global.read_only; 仍返回 OFF,大概率是配置未加载或被覆盖。
- 确认配置写在正确 section 下:
[mysqld]段内,不能放在[client]或[mysql] - 检查是否有多个配置文件被读取(
mysqld --help --verbose | grep "Default options"),避免/etc/my.cnf和/etc/mysql/mysql.conf.d/mysqld.cnf冲突 - 确认没有在启动命令行中用
--read-only=OFF显式关闭,它会覆盖配置文件值 - 某些云数据库(如阿里云 RDS、AWS RDS)禁止修改
read_only,需通过控制台开关,配置文件修改无效
read_only 和 super_read_only 的区别与配合使用
super_read_only 是 5.7.8+ 引入的增强参数,它不仅限制普通用户,还会阻止有 SUPER 权限的用户写入(除复制线程外)。
- 启用顺序很重要:先设
read_only=ON,再设super_read_only=ON;否则后者可能拒绝生效 - 主从切换时,从库应同时开启两者:
read_only=ON+super_read_only=ON,防止人为提升为新主库后误写 - 注意:开启
super_read_only后,连SET GLOBAL read_only = OFF都会被拒绝,必须先关它才能调read_only - 查看状态统一用:
SELECT @@global.read_only, @@global.super_read_only;
只读模式下仍可能触发写操作的隐蔽场景
即使 read_only=ON,某些语句表面看是查询,实则隐式修改数据,容易被忽略。
-
SELECT ... INTO OUTFILE本身不写表,但若搭配触发器或函数调用,可能间接触发写入(取决于函数逻辑) - 使用
INSERT ... SELECT时,哪怕SELECT部分查的是只读库,整个语句仍是写操作,会被直接拒绝 - 开启
log_bin且 binlog_format=STATEMENT 时,某些函数(如NOW()、UUID())在从库执行可能引发不一致,虽不报错但破坏只读语义 - 监控类工具(如 pt-heartbeat)若配置了写权限,在只读实例上运行会失败,需确保其连接账号只有
SELECT权限
真正安全的只读,靠的是权限控制 + 参数限制 + 连接账号分离,单靠一个 read_only 帐户拦不住所有路径。











