MySQL只读模式下仍可创建临时表,因CREATE TEMPORARY TABLES权限独立于read_only,且临时表仅会话可见、不持久化、不写binlog;需按库精确授权该权限。

因为 CREATE TEMPORARY TABLES 权限独立于 read_only 设置,且默认不被 read_only 拦截
read_only=1 不影响临时表创建
MySQL 的 read_only 参数只阻止对持久化数据的写操作(如 INSERT、UPDATE、DROP、CREATE TABLE),但临时表不落盘、不进 binlog、不参与复制,其生命周期仅限当前会话。因此,即使 read_only = 1,只要用户拥有 CREATE TEMPORARY TABLES 权限,CREATE TEMPORARY TABLE 语句仍能成功执行。
错误信息不会是 “The MySQL server is running with the --read-only option”,而是典型的权限类报错(如 ERROR 1142)——说明问题出在权限缺失,而非只读模式拦截。
只读实例上仍需显式管控 CREATE TEMPORARY TABLES 权限
云数据库(如阿里云 RDS、腾讯云 CDB)的只读实例虽默认开启 read_only=1,但权限系统完全独立:mysql 系统库不复制,账号和权限必须手动同步。常见疏漏包括:
- 主库上给只读账号授了
SELECT,却忘了补CREATE TEMPORARY TABLES—— 导致应用连只读实例后建临时表失败 - 只在主库执行了
GRANT CREATE TEMPORARY TABLES ON *.*,但没在只读实例上重复执行 —— 权限根本不存在 - 误以为
GRANT SELECT ON db.*自动包含临时表权限,实际二者完全解耦 - 用了通配主机(如
'ro_user'@'%'),但只读实例防火墙或代理只放行特定内网段,导致连接被拒绝,误判为权限问题
为什么允许临时表不破坏只读语义?
临时表本质上是会话级内存/磁盘缓存结构,它不能:
- 被其他会话访问(
SHOW TABLES看不到,必须用SHOW FULL TABLES WHERE Table_type = 'TEMPORARY') - 修改任何永久表数据(
INSERT INTO real_table SELECT * FROM tmp会因缺少 INSERT 权限失败) - 触发 DDL 变更(
DROP TABLE real_table或ALTER TABLE real_table均被权限拦截) - 影响 GTID 或复制一致性(不写 binlog,不发到从库)
所以,只要权限精准控制在目标库范围(例如 GRANT CREATE TEMPORARY TABLES ON `app_db`.*),它就是安全的中间计算手段。真正危险的是授予 ON *.* —— 用户可能在 information_schema 或 performance_schema 下建临时表,引发不可预知的资源争用或元数据查询干扰。
最容易被忽略的一点:权限变更后,旧连接不会自动刷新权限;REVOKE 或 GRANT 生效需新连接,而应用连接池往往长连接复用,导致“明明 revoke 了,还能建表”的假象。











