MySQL 8.0角色仅支持库表级权限,不支持列级(如GRANT SELECT(id,name))或行级语法,报ERROR 1142是因语法被拒绝;细粒度控制必须组合视图(SQL SECURITY DEFINER)、存储函数、映射表及严格权限隔离实现。

MySQL 8.0 的角色本身不支持“细粒度”权限语法(比如列级、行级、条件级),所谓细粒度必须靠角色 + 视图/函数/权限隔离组合实现;单独用 CREATE ROLE 和 GRANT 只能做库表级控制。
为什么直接 GRANT SELECT(id, name) ON t1 TO 'role' 会报错
MySQL 角色不支持列级授权,任何带括号字段列表的 GRANT 都会触发 ERROR 1142 (42000)。这不是权限没开,而是语法被拒绝——角色权限粒度止步于表级。
- 想限制用户只查
t1.id和t1.name?必须建视图:CREATE VIEW v_t1_basic AS SELECT id, name FROM t1 - 视图要可信赖,必须用
SQL SECURITY DEFINER定义,并由高权限账号(如'admin'@'localhost')作为DEFINER - 然后把
SELECT权限授给角色:GRANT SELECT ON mydb.v_t1_basic TO 'report_role' - 同时务必收回对基表的权限:
REVOKE SELECT ON mydb.t1 FROM 'report_role'
如何让只读角色真正支持 SHOW CREATE TABLE
只授 SELECT ON report_db.* 后,执行 SHOW CREATE TABLE sales_summary 仍报 ERROR 1142,因为该语句依赖 information_schema.TABLES 表。
- 必须显式补授权:
GRANT SELECT ON `information_schema`.`TABLES` TO 'report_role' - 如需字段类型或注释(例如报表工具自动取 schema),再加:
GRANT SELECT ON `information_schema`.`COLUMNS` TO 'report_role' - 禁止用
GRANT SELECT ON information_schema.*——部分表(如PROCESSLIST)需要额外权限,反而暴露风险 - 角色名必须带主机名,推荐统一用
'report_role'@'%',避免后续绑定用户时因 host 不匹配失败
SET DEFAULT ROLE 是权限生效的硬门槛
GRANT 'report_role' TO 'bi_user'@'10.20.%' 只是写入 mysql.role_edges,用户登录后 CURRENT_ROLE() 返回 NULL,所有查询仍被拒。
- 必须执行:
ALTER USER 'bi_user'@'10.20.%' DEFAULT ROLE 'report_role'@'%' - 该语句三个前提缺一不可:执行者有
ROLE_ADMIN权限;'report_role'@'%'已存在且已授过权;'bi_user'@'10.20.%'用户已存在(哪怕只有USAGE) - 验证是否激活:
SELECT CURRENT_ROLE()(连接后立即查),不是看SHOW GRANTS FOR 'bi_user'@'10.20.%'——它默认不展开角色权限 - 要看真实权限,得用:
SHOW GRANTS FOR 'bi_user'@'10.20.%' USING 'report_role'@'%'
角色功能必须手动启用,重启即失效
首次执行 CREATE ROLE 就报 ERROR 3719,不是语法错,是全局开关未开。
- 由
root或高权限用户执行:SET GLOBAL activate_all_roles_on_login = ON - 并授予管理权:
GRANT ROLE_ADMIN ON *.* TO 'admin_user'@'%' -
FLUSH PRIVILEGES刷新元数据 - 但这是临时设置——MySQL 重启后失效。生产环境必须写入
my.cnf的[mysqld]段:activate_all_roles_on_login=ON,然后重启服务
最容易被忽略的是:角色只是权限容器,它不自动解决行级隔离、连接池混淆、用户名解析歧义等问题。一旦涉及业务维度的“谁能看到谁的数据”,就必须跳出角色机制,用 DEFINER 视图 + 存储函数 + 映射表闭环实现,否则看似配置完成,实则权限形同虚设。


















