grant create temporary tables on db_name. 是唯一有效写法,mysql 5.7及更早版本不支持on .*,8.0+虽语法通过但行为不可靠;该权限独立于select、create或usage,必须显式授予且与源表select权限分离。

GRANT CREATE TEMPORARY TABLES ON db_name.* 是唯一有效写法
MySQL 不接受 GRANT CREATE TEMPORARY TABLES ON *.*(5.7 及更早版本直接报错),也不支持表级或全局通配授权。必须指定具体数据库名,哪怕你只是想在 test_db 里建个临时表做测试,也得写成:
GRANT CREATE TEMPORARY TABLES ON test_db.* TO 'dev_user'@'localhost';
常见错误包括:
- 漏掉数据库名,写成
ON *.*或ON .*—— MySQL 8.0+ 虽不报错但行为不可靠,5.7 会拒绝执行 - 误用反引号包裹用户名或主机名,如
'`dev_user`'@'`localhost`'—— 语法错误 - 授权后没验证:用户仍报
ERROR 1142 (42000): CREATE TEMPORARY TABLES command denied,大概率是库名拼错或 host 不匹配
为什么 SELECT 权限不能代替 CREATE TEMPORARY TABLES
这是最常被误解的点。有 SELECT 权限 ≠ 能建临时表;有 CREATE 权限 ≠ 能建临时表;USAGE 更是完全无关。MySQL 把 CREATE TEMPORARY TABLES 当作独立权限位处理。
典型表现:
- 用户能查
information_schema.tables,却执行CREATE TEMPORARY TABLE tmp AS SELECT 1失败 - 应用连接成功、查询正常,但某条带子查询的 SQL 突然卡住或报错 —— 底层优化器试图建内部临时表,但权限不足
- 用
GRANT ALL PRIVILEGES ON db.*授权后仍失败 ——ALL不包含CREATE TEMPORARY TABLES,必须显式加授
生产环境必须避开的三个坑
权限配对错误、作用域错位、残留永久表,三者都可能引发线上事故。
-
CREATE TEMPORARY TABLE语句漏写TEMPORARY关键字,变成CREATE TABLE—— 创建的是永久表,进入权限系统,后续可能被其他用户读取或误删 - 给
app_db授了CREATE TEMPORARY TABLES,但临时表AS SELECT的源表来自log_db—— 会因缺少log_db的SELECT权限而失败,和临时表权限无关 - 用
GRANT CREATE TEMPORARY TABLES ON *.*授权后,用户在mysql或performance_schema库下建临时表 —— 虽然语法通过,但属高危操作,可能干扰系统行为
替代方案:用 CTE 避开权限问题
如果你无法快速修改权限(比如只读账号、第三方 SaaS 数据库),WITH 子句是安全替代项。它不依赖 CREATE TEMPORARY TABLES 权限,且语义等价:
WITH user_summary AS (SELECT user_id, COUNT(*) c FROM orders GROUP BY user_id) SELECT u.name, s.c FROM users u JOIN user_summary s ON u.id = s.user_id;
注意:WITH 是 MySQL 8.0.1+ 特性,5.7 及更早版本不支持;CTE 生命周期仅限单条语句,不能跨查询复用 —— 这反而是优点,避免临时表残留或命名冲突。
真正麻烦的不是“怎么加权限”,而是搞清权限边界在哪:临时表权限管建表动作,源表权限管数据来源,两者缺一不可,且各自独立校验。











