应先执行SHOW GRANTS FOR CURRENT_USER();检查输出是否含CREATE TEMPORARY TABLES,若无则权限缺失;ERROR 1142为已登录后的权限问题,ERROR 1045为登录失败,需用SELECT USER(), CURRENT_USER();确认实际匹配账号。

确认用户是否真有 CREATE TEMPORARY TABLES 权限
很多报错看似是“不能建临时表”,实际是权限没显式授予。MySQL 不会默认给所有用户这个权限,哪怕你有 CREATE 或 ALL PRIVILEGES(除非作用于全局 *.*),也得单独授。执行:
SHOW GRANTS FOR CURRENT_USER();
重点看输出里有没有 CREATE TEMPORARY TABLES 这一项。如果没有,说明权限缺失;如果只有 USAGE,那等于啥也没给。
常见误区:
- 误以为
GRANT ALL ON db1.*包含临时表权限——它不包含,CREATE TEMPORARY TABLES是独立权限,且只能授给数据库级或全局级 - 用
GRANT ALL PRIVILEGES ON *.*却漏了WITH GRANT OPTION,结果自己能建,但转授给其他账号时失败 - 在 MySQL 8.0+ 中用了角色(role),但没激活:
SET ROLE 'temp_role';或配置activate_all_roles_on_login=ON没开
区分 ERROR 1142 和 ERROR 1045 的真实含义
看到“command denied”别急着加权限——先分清错误类型:
-
ERROR 1142 (42000): CREATE TEMPORARY TABLES command denied to user 'u'@'h' for database 'db':已登录成功,纯权限问题,查SHOW GRANTS即可定位 -
ERROR 1045 (28000): Access denied for user 'u'@'h':根本没登录进去,可能是密码错、plugin 不兼容(如caching_sha2_password被旧客户端拒绝)、或account_locked=1
验证方式很简单:
SELECT USER(), CURRENT_USER();
如果返回空或报错,说明连接阶段就失败了,别再往下查授权。
检查是否被 host 匹配规则“绕过”了预期账号
MySQL 认证时按 User+Host 元组精确匹配,而 Host 字段区分大小写、且通配符优先级隐含陷阱。例如:
- 你创建了
'app'@'192.168.5.%'并授了临时表权限 - 但从
192.168.5.100连接时,MySQL 却匹配到了'app'@'%'——而这个账号可能只给了USAGE - 或者你连的是
localhost,但账号只建了'app'@'127.0.0.1',两者在 MySQL 内部被视为不同 host
查真实匹配结果:
SELECT Host, User, authentication_string, account_locked FROM mysql.user WHERE User = 'app';
注意比对连接时用的 host 是否完全一致(包括 localhost vs 127.0.0.1)。
临时表权限与 WITH 子句不是一回事
MySQL 8.0+ 的 WITH 语句(CTE)不需要 CREATE TEMPORARY TABLES 权限,但它也不是“替代方案”——它是语法层面的逻辑临时结果集,不落地、不可重复引用、不能加索引、也不能在多个语句间共享。
如果你遇到的场景是:
- 需要在存储过程里多次查询同一中间结果 →
WITH不行,必须用临时表 - 需要在触发器里建表 → 直接禁止,
ERROR 1314,WITH同样不支持 - 想绕过权限申请 →
WITH可用,但要重写整个逻辑,且性能未必更好(尤其大结果集)
真正容易被忽略的点是:有些 DBA 会禁用 CREATE TEMPORARY TABLES 权限来防滥用,但忘了告诉开发,后者一看到 WITH 就以为“能用了”,结果上线后发现 CTE 在复杂嵌套下被优化器展开成多次子查询,反而更慢。


















