MySQL GRANT不支持表名通配符,必须显式列出每张表;若存在库级权限需先REVOKE;推荐用视图聚合前缀表并授权,或按业务域分库实现可维护权限控制。

GRANT 语句必须带完整 db_name.table_name,不能用通配符匹配前缀
MySQL 的 GRANT 语法不支持表名通配符(比如 app_% 或 log_*),写 GRANT SELECT ON mydb.app_% TO 'u'@'%' 会直接报错 ERROR 1103 (42000): Incorrect table name 'app_%'。它只认字面量表名,不解析模式匹配。
常见错误是误以为类似 shell 的通配逻辑能用在权限系统里——实际没有这层机制。你必须把每张符合前缀的表都列出来,例如:
GRANT SELECT ON mydb.app_users TO 'u'@'%'; GRANT SELECT ON mydb.app_orders TO 'u'@'%'; GRANT SELECT ON mydb.app_logs TO 'u'@'%';
如果表数量多且动态增长,靠人工维护不可持续,得换思路。
先 REVOKE 所有宽泛权限,否则表级授权被覆盖
如果你之前执行过 GRANT SELECT ON mydb.* TO 'u'@'%',哪怕后续再给单表授权,用户依然能查整个库——因为库级权限优先级高于表级,它“盖住”了更细粒度的限制。
真正生效的前提是清理干净更粗的权限:
- 运行
SHOW GRANTS FOR 'u'@'%',确认输出里没有ON mydb.*或ON *.* - 执行
REVOKE SELECT ON mydb.* FROM 'u'@'%' - 再逐个
GRANT SELECT ON mydb.app_xxx TO 'u'@'%' - 最后
FLUSH PRIVILEGES,并用新连接验证
用视图 + 前缀命名约定实现可维护的“逻辑白名单”
当业务表按前缀批量创建(如 report_202401, report_202402),硬写每张表的 GRANT 会随时间崩坏。此时推荐建一个汇总视图,把所有目标前缀表 UNION ALL 起来:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
CREATE VIEW mydb.v_app_tables AS SELECT 'users' AS source, id, name, created_at FROM mydb.app_users UNION ALL SELECT 'orders' AS source, id, amount, status FROM mydb.app_orders UNION ALL SELECT 'logs' AS source, id, level, msg FROM mydb.app_logs;
然后只授这个视图权限:GRANT SELECT ON mydb.v_app_tables TO 'u'@'%'。好处是新增表时只需改视图定义,不用动权限;缺点是无法写入、且 source 字段需手动维护区分来源。
注意:视图底层表仍需确保该用户无直连权限,否则可绕过。
真正隔离且可扩展的方案:分库或分表 + 表级权限组合
如果前缀本质是业务域划分(如 finance_*, marketing_*),最稳妥的做法是物理分离:
- 把
finance_user相关表全挪到finance_db库,只授GRANT SELECT ON finance_db.* TO 'u_f'@'%' - 或拆成独立表名(
finance_transactions,marketing_campaigns),再按需单表授权 - 避免用分区表打前缀主意——MySQL 不支持分区级权限,
PARTITION(p2)只能在查询中显式指定,不能用于授权
容易被忽略的一点:权限变更后,旧连接不会自动更新上下文。务必断开重连,或用 mysql -u u -p -h host 新起客户端测试,别在原会话里 USE mydb 后直接试。否则看到的仍是缓存权限。










