从库只读必须设 read_only 和 super_read_only;仅 read_only 无法阻止 SUPER 用户写入,super_read_only 才能真正禁止所有写操作,且需配置正确顺序并配合权限管控与网络隔离。

从库只读必须设 read_only,但光设它不够
只设 read_only = ON 是最常见做法,但它只拦普通用户——拥有 SUPER 权限的账号(比如 root)仍能执行 INSERT、CREATE FUNCTION、DROP TABLE 甚至 EVENT。这在主从同步场景下很危险:万一运维误连从库并用 root 清了某张表,binlog 不会记录,主库不会同步,数据就永久不一致了。
- 临时启用(重启失效):
SET GLOBAL read_only = ON; - 永久生效需写进配置文件:
/etc/my.cnf的[mysqld]段下加read_only = ON,再systemctl restart mysql - 检查是否生效:
SHOW VARIABLES LIKE 'read_only';返回ON即成功
super_read_only 才是真正兜底的只读开关
super_read_only = ON 在 MySQL 5.7.8+ 引入,开启后连 SUPER 用户也无法写入,连创建存储过程、触发器、EVENT 都被禁止——这才是“从库不该动”的完整语义。它和 read_only 是联动的:super_read_only = ON 会自动把 read_only 设为 ON;反过来,read_only = OFF 也会强制关掉 super_read_only。
- 动态启用(需 SUPER 权限):
SET GLOBAL super_read_only = ON; - 配置文件写法(推荐):
super_read_only = ON必须放在read_only = ON后面,否则启动报错 - MySQL 8.0+ 支持
SET PERSIST super_read_only = OFF持久化关闭,但生产环境不建议用
写操作被拒时看到的错误不是配置失败,而是正常保护
从库设好只读后,任何写操作都会立刻报错,这不是故障,是预期行为。典型错误信息是:ERROR 1290 (HY000): The MySQL server is running with the read-only option so it cannot execute this statement。这个报错会出现在所有写类语句上,包括 UPDATE、TRUNCATE、ANALYZE TABLE(8.0+ 对系统表也生效),甚至 CREATE TEMPORARY TABLE(部分版本)。
- 应用连接从库报这个错?先确认 JDBC URL 是否带了
readOnly=true或useLocalSessionState=true,否则驱动可能缓存了旧事务状态 - 监控脚本如果用了
root账号执行SELECT+SHOW PROCESSLIST,没问题;但若混了FLUSH STATUS就会失败 - 已存在的未提交事务,在
read_only开启后只能ROLLBACK,不能COMMIT
别漏掉权限和网络层的配套动作
只读参数只是第一道防线。如果主库同步了用户表(mysql.user),那主库上给 app_user 授的 ALL PRIVILEGES 也会落到从库,此时即使开了 super_read_only,只要该账号没被 revoke SUPER,它理论上还能提权——所以必须清理权限链。
- 撤销高危权限:
REVOKE SUPER ON *.* FROM 'app_user'@'%'; - 绑定内网监听:
bind-address = 192.168.10.5,避免从库暴露在公网 - 禁用 DNS 反查:
skip_name_resolve = ON,既提速又防潜在解析劫持 - MySQL 8.0+ 建议用角色管理:
CREATE ROLE 'ro_role'; GRANT SELECT, REPLICATION CLIENT ON *.* TO 'ro_role';,再把账号加到角色里
最常被跳过的其实是复制线程本身:read_only 不影响 SQL_THREAD 应用 relay log,但如果你手动 STOP SLAVE 后忘了 START SLAVE,或者只启了 IO 线程没启 SQL 线程,从库就会静默落后——这时候只读开着,数据却早已不一致了。


















