read_only和super_read_only的核心区别在于权限绕过:read_only=on时super用户仍可写,而super_read_only=on时连super用户也被拦截,且启用时自动设read_only=on;若需彻底锁死写入,必须使用super_read_only。

read_only 和 super_read_only 的区别必须分清
MySQL 没有“数据库级只读”这个独立开关,所谓只读,本质是靠 read_only 和 super_read_only 这两个全局系统变量控制的。它们不是针对某张表或某个库,而是作用于整个实例——所有连接进来、尝试写入的会话都会被拦截。
关键差异在于权限绕过:
-
read_only = ON:普通用户(非SUPER权限)执行INSERT/UPDATE/DELETE会报错ERROR 1290 (HY000): The MySQL server is running with the --read-only option...;但root或带SUPER权限的账号仍可写 -
super_read_only = ON:连SUPER用户也拦住,连CREATE FUNCTION、INSTALL PLUGIN、ANALYZE TABLE都会被拒绝;它启用时自动把read_only设为ON;反过来,SET GLOBAL read_only = OFF会顺带关掉super_read_only
所以如果你真要锁死写入(比如主库做迁移前的最终冻结),光设 read_only 不够,得上 super_read_only。
MyISAM 表不能靠 read_only 实现真正只读
read_only 和 super_read_only 对存储引擎无差别生效——但 MyISAM 本身不支持事务、也不走 InnoDB 那套 MVCC 机制,它的文件层面更“裸”。这意味着:
- 即使
read_only = ON,MyISAM 表仍可能被FLUSH TABLES WITH READ LOCK之外的方式间接修改(比如直接操作.MYD文件,虽然不推荐) -
innodb_read_only = ON是另一个维度:它让 InnoDB 存储引擎拒绝所有写操作(包括 DDL),且必须重启生效;但它对 MyISAM 表完全无效 - MyISAM 表若需强只读,只能靠操作系统层文件权限(
chown mysql:mysql /var/lib/mysql/dbname/*.MYD+chmod 444)或FLUSH TABLES WITH READ LOCK配合SET GLOBAL read_only = ON
简单说:MyISAM 的“只读”得靠外力加固,read_only 只管 SQL 层面,不管文件层。
transaction_read_only 是会话级开关,别和全局搞混
transaction_read_only(旧名 tx_read_only)是会话级参数,只影响当前连接后续开启的事务,对已存在的事务或其它连接完全没用。
- 设置方式:
SET SESSION transaction_read_only = ON或连接时加?transaction_read_only=1参数 - 它不阻止
CREATE TABLE、DROP TABLE等 DDL,只限制事务内 DML(INSERT/UPDATE/DELETE) - 它和
read_only无关:即使全局read_only = OFF,你也可以在某个连接里设transaction_read_only = ON;反之,全局开了read_only,该参数设成OFF也没用——写操作照样被拦
这参数适合应用层按需控制单个连接的行为,比如报表查询连接默认开它,避免误写;但它不是运维部署只读实例的工具。
innodb_read_only 必须重启才生效,且影响远超名字所见
innodb_read_only = ON 是个硬核开关,8.0 起它不只是让 InnoDB 表只读,而是让整个数据目录(包括系统表)都变成只读状态。
- 无法在线修改,必须写进配置文件(
my.cnf的[mysqld]段),然后重启 MySQL - 开启后,连
ANALYZE TABLE、OPTIMIZE TABLE、ALTER TABLE ... ENGINE=InnoDB都会失败,错误类似Table 'xxx' is read only - 它不依赖
read_only,也不受super_read_only影响;它是存储引擎层的物理只读,比 SQL 层的限制更底层 - 如果实例里混用了 MyISAM 和 InnoDB,这个参数只约束 InnoDB 表;MyISAM 表仍可通过 SQL 写入(前提是
read_only没开)
真正需要“磁盘级只读”的场景(比如归档库挂只读 NFS 卷),才考虑它;日常从库只读,super_read_only 就够了,别动它。











