喵喵宠物医院
86.09M · 2026-04-08
在 MySQL/GreatSQL 数据库管理中,通过设置只读模式来控制实例的数据写入权限是一项常见的运维操作,尤其在搭建主从复制、执行备份、进行维护或实现读写分离时至关重要。MySQL/GreatSQL 提供了多个与只读相关的系统参数,它们从不同维度对实例的读写能力进行约束。理解这些参数的作用、区别及相互影响,能够帮助我们更精确地控制数据库的行为,确保数据一致性和系统高可用。
该参数为静态参数,仅能在 MySQL/GreatSQL 服务启动阶段配置,运行时无法修改。
从 MySQL/GreatSQL 8.0.* 版本开始,启用该变量后,所有存储引擎的表创建、删除操作都会被禁止。核心原因是:无论操作的表属于哪种存储引擎,表的增删及其他涉及数据字典修改的表操作,都会改动mysql系统库中的数据字典表,而这类数据字典表均基于 InnoDB 存储引擎,因此innodb_read_only启用后,相关修改操作会被直接限制。
启用该参数后,即使是超级管理员 root 用户,其相关操作也会受到严格限制。
greatsql> CREATE DATABASE test;ERROR 1836 (HY000): Running in read-only modegreatsql> CREATE TABLE t10 (c1 int);ERROR 1836 (HY000): Running in read-only modegreatsql> DROP TABLE sbtest1;ERROR 3604 (HY000): Storage engine cant DROP TABLE 'sysbench.sbtest1'greatsql> DELETE FROM sbtest1 WHERE id>100;ERROR 1015 (HY000): Cant lock file (errno: 165 - TABLE is read only)greatsql> ALTER TABLE sbtest1 DROP key k_1;ERROR 1836 (HY000): Running in read-only mode因mysql系统库中权限表、插件表、函数表等均为 InnoDB 引擎,启用innodb_read_only后,以下操作均会执行失败:
# 创建用户、修改用户greatsql> CREATE USER t1@'%' IDENTIFIED BY 'abc123';ERROR 3501 (HY000): The ACL operation failed due to the following error FROM SE: errcode 165 - TABLE is read onlygreatsql> ALTER USER tt@'%' IDENTIFIED BY 'abc123';ERROR 3501 (HY000): The ACL operation failed due to the following error FROM SE: errcode 165 - TABLE is read only启用该参数后,执行ANALYZE TABLE会因无法更新数据字典中的统计信息表而失败:
greatsql> ANALYZE TABLE t1;+-----------+---------+----------+----------------------------------------------------------------+* TABLE * Op * Msg_type * Msg_text *+-----------+---------+----------+----------------------------------------------------------------+* test01.t1 * analyze * Warning * InnoDB: Running in read-only mode ** test01.t1 * analyze * Error * Running in read-only mode ** test01.t1 * analyze * Error * Unable to store dynamic TABLE statistics INTO data dictionary. ** test01.t1 * analyze * status * Unable to write TABLE statistics to DD TABLEs *+-----------+---------+----------+----------------------------------------------------------------+4 rows in set (0.01 sec)若数据库中已存在 MyISAM 等非 InnoDB 引擎的表,仅可对表内数据执行 DML 操作,表结构的 DDL 操作仍会被禁止;若强制执行 DDL,可能出现底层文件丢失但数据库元数据残留的异常情况。
数据DML操作可正常执行
greatsql> INSERT INTO t3 VALUES (1),(2);Query OK, 2 rows affected (0.01 sec)Records: 2 Duplicates: 0 Warnings: 0greatsql> DELETE FROM t3;Query OK, 4 rows affected (0.00 sec)表DDL操作执行失败
greatsql> DROP TABLE t3;ERROR 1036 (HY000): TABLE 'columns' is read only异常情况:表底层文件丢失,元数据仍存在,无法访问表
greatsql> SHOW CREATE TABLE t3\GERROR 1017 (HY000): Cant find file: 't3' (errno: 2 - No such file or directory)greatsql> SHOW TABLES;+------------------+* TABLES_in_test01 *+------------------+* t1 ** t2 ** t3 *+------------------+3 rows in set (0.00 sec)greatsql> SELECT * FROM t3;ERROR 1017 (HY000): Cant find file: 't3' (errno: 2 - No such file or directory)# 针对上述元数据残留问题,可通过DROP TABLE IF EXISTS语句清理数据库中的残留表信息:greatsql> DROP TABLE IF EXISTS t3;Query OK, 0 rows affected, 1 warning (0.01 sec)该参数为动态参数,默认处于禁用状态。启用后,服务器会禁止普通用户执行任何更新操作,拥有CONNECTION_ADMIN权限(或已弃用的SUPER权限)的用户除外,是数据库实例级的只读控制参数。
源服务器上 read_only 的配置变更不会复制到副本服务器,副本可独立于源服务器设置该参数的值,不受源库配置影响.
(1)该参数与super_read_only存在强联动关系:
super_read_only时,会隐式强制 read_only 设置为 ON;read_only置为 OFF 时,会隐式强制 super_read_only 设置为 OFF。(2)当read_only和super_read_only同时启用时,服务器仍允许执行以下操作,不做只读限制:
ANALYZE TABLE或OPTIMIZE TABLE语句,两类操作仅做表分析 / 优化,不修改表结构和数据;(3)尝试启用read_only时(包括因启用super_read_only触发的隐式启用),需满足以下规则,否则会执行失败或被阻塞:
FLUSH TABLES WITH READ LOCK获取的全局读锁时,可正常启用read_only(全局读锁不涉及表级锁,无冲突)。该参数为动态参数,默认处于禁用状态,是比read_only更严格的实例级只读控制参数。启用后,服务器会禁止所有客户端的更新操作,即使是拥有CONNECTION_ADMIN或SUPER权限的特权用户也不例外。
与read_only一致,源服务器上super_read_only的配置变更不会复制到副本服务器,副本可独立设置该参数的值。
核心限制范围
除常规的 DML、DDL 操作外,启用super_read_only后,表面非更新但会修改mysql系统表的操作也会被禁止,包括:
以上操作的禁用原因均为会改动mysql系统库中的相关系统表。
对事件调度器(Event Scheduler)的影响
(1)若事件调度器处于启用状态,启用super_read_only会导致其无法更新事件数据字典表中的「最后执行」时间戳,进而触发以下结果:
(2)针对事件调度器的恢复,MySQL不同版本有不同规则:
super_read_only启用后再禁用,服务器会根据需要自动重启事件调度器;该参数为事务层面的读写控制开关,核心作用是通过开关限定指定作用域内事务是否允许执行写操作,与实例级的只读控制参数无关联。
取值:仅支持OFF(读写模式,默认值)和ON(只读模式);
作用域:分为全局级、会话级、下一个事务级,不同作用域的生效范围和持续时间不同。
SET GLOBAL transaction_read_only = ON;SET SESSION transaction_read_only = ON;SET @@transaction_read_only = ON;全局级和会话级启用只读后,对事务内的DML 和 DDL 操作均会禁止,执行时报错一致。
1. 设置会话级只读greatsql> SET SESSION transaction_read_only=ON;2. 执行DML操作,报错greatsql> INSERT INTO test.t01 VALUES('c',null,'c',null);ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.3. 执行DDL操作,报错greatsql> CREATE TABLE test.t16 (c1 int);ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.4. 执行账户管理DDL,报错greatsql> CREATE user test01@'%';ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.下一个事务级启用只读后,仅对 DML 操作生效,DDL 操作不受限制,且配置仅对单次事务有效。
1. 设置下一个事务级只读greatsql> SET @@transaction_read_only=ON;2. 执行DML操作,报错greatsql> INSERT INTO test.t01 VALUES('c',null,'c',null);ERROR 1792 (25006): Cannot execute statement in a READ ONLY transaction.3. 重新设置下一个事务级只读(上一步DML已消耗该配置,需重新设定)greatsql> SET @@transaction_read_only=ON;4. 执行DDL操作,成功执行greatsql> CREATE TABLE test.t15 (c1 int);Query OK, 0 rows affected (0.04 sec)本文详细解析了 MySQL/GreatSQL 中innodb_read_only、read_only、super_read_only、transaction_read_only四类只读参数的核心作用、适用场景、限制范围及相互关系,核心要点总结如下:
参数层级与定位清晰
super_read_only 启用会强制开启 read_only,关闭 read_only 会强制关闭 super_read_only。