MySQL 8.0.1前不支持CREATE ROLE,报ERROR 1064即因版本过低;8.0+需注意角色名勿用反引号/双引号,且必须GRANT角色给用户并SET DEFAULT ROLE才生效。

CREATE ROLE 报错 ERROR 1064 是版本问题,不是语法写错了
执行 CREATE ROLE 'app_reader' 直接报错 ERROR 1064 (42000),99% 是 MySQL 版本低于 8.0.1。角色功能是 8.0.1 才正式引入的,5.7 及更早版本压根不识别这个语法。
先确认版本:SELECT VERSION();。如果是 5.7.32 或类似输出,就别折腾角色了,老实用 GRANT SELECT ON mydb.* TO 'u1'@'%' 直接授用户权限。
若确认是 8.0+ 但还报错,检查是否用了反引号或双引号包角色名——MySQL 角色名默认不加引号;加了单引号('app_reader')是对的,但写成 `app_reader` 或 "app_reader" 在某些配置下会触发语法错误。
角色创建后必须显式授予用户并 SET DEFAULT ROLE 才生效
角色只是个空容器,CREATE ROLE 'app_writer' + GRANT INSERT, UPDATE ON app_db.* TO 'app_writer' 完事,用户还是啥权限都没有。常见误操作是以为“赋权给角色=用户自动获得”,结果开发连 SELECT 都被拒。
-
GRANT 'app_writer' TO 'dev_user'@'localhost';—— 这步把角色“分配”给用户,但不激活 -
SET DEFAULT ROLE 'app_writer' TO 'dev_user'@'localhost';—— 这步才让该用户每次登录自动启用该角色 - 漏掉第二步,用户登录后执行
SELECT CURRENT_ROLE();返回NULL,SHOW GRANTS;也看不到任何角色权限
如果不想设默认角色,用户可手动执行 SET ROLE 'app_writer';,但这只在当前会话有效,断开重连就得重设。
REVOKE FROM 后面跟的是角色名还是用户名,决定权限回收范围
回收权限时,FROM 后的对象类型直接决定影响面:
-
REVOKE SELECT ON app_db.* FROM 'app_reader';—— 从角色本身移除权限,所有通过该角色获得SELECT的用户立即失效 -
REVOKE SELECT ON app_db.* FROM 'dev_user'@'localhost';—— 只撤销该用户的直授权限,对其通过角色继承的权限完全无影响 - 查用户到底有哪些角色:
SELECT * FROM mysql.role_edges WHERE to_user = 'dev_user' AND to_host = 'localhost';
生产环境改权限前,务必先用 SHOW GRANTS FOR 'dev_user'@'localhost' USING 'app_reader'; 确认该角色当前确实赋予了哪些权限——SHOW GRANTS 默认不显示角色继承权限,容易误判。
WITH GRANT OPTION 别乱加,尤其别加在角色上
给角色加 WITH GRANT OPTION(如 GRANT UPDATE ON sales.* TO 'mgr_role' WITH GRANT OPTION),等于授权所有持有该角色的用户都能再转授 UPDATE 权限,包括新建用户、新建角色、甚至回授给自己。
这会导致权限链失控,审计困难,回收成本极高。线上库应禁用所有角色的 WITH GRANT OPTION,提权操作统一走 DBA 审批流程。
已加上的要回收:REVOKE GRANT OPTION ON sales.* FROM 'mgr_role';。注意,这不是撤销 UPDATE 权限本身,而是撤销“再授予权限”的能力。
最常被忽略的其实是 SET DEFAULT ROLE 这一步——配置完角色、赋完权、授完角色,以为万事大吉,结果用户一登录就 Access denied。角色不是开关,是钥匙串;给了钥匙串,还得告诉用户“这串里哪把该插进锁孔”。











