MySQL原生不支持表名前缀通配符授权,如GRANT SELECT ON db.\user_%\`.*`语法错误;必须显式列举表名、使用视图封装、代理层拦截或应用层校验等替代方案。
MySQL 中用 GRANT 限制表名前缀访问
直接说结论:mysql 原生不支持「表名前缀通配符授权」,比如 grant select on db.`user_%`.* to 'u'@'%' 是语法错误,会报 error 1064 (42000)。必须用具体表名或数据库级权限兜底。
替代方案:用 GRANT ... ON database.table 显式列出表
最稳妥的做法是把所有匹配前缀的表名一次性列出来——前提是表数量可控、变动不频繁。
- 先查出当前所有匹配前缀的表:
SELECT table_name FROM information_schema.tables WHERE table_schema = 'db' AND table_name LIKE 'log_%'; - 生成授权语句(建议用脚本拼接,避免手误):
GRANT SELECT ON db.log_202401 TO 'u'@'%'; GRANT SELECT ON db.log_202402 TO 'u'@'%'; - 注意:每条
GRANT语句只支持单表,不能写成GRANT SELECT ON db.`log_%` TO ... - 执行后记得
FLUSH PRIVILEGES;,否则权限不生效
动态场景下只能靠应用层或代理层拦截
如果表按月自动创建(如 log_202403、log_202404),人工维护授权不现实。这时 MySQL 本身无解,得换思路:
- 在应用代码里硬编码表名白名单,所有 SQL 拼接前校验
table_name.startswith('log_') - 用 ProxySQL 或 MaxScale 做 SQL 重写/拦截,在代理层拒绝非前缀表的
SELECT、INSERT - 改用视图封装:建一个
log_all视图 UNION 所有log_%表,只给用户授视图权限 —— 但要注意视图性能和 DML 限制
别踩 mysql.db 表直改这个坑
有人想绕过 GRANT 语法,直接 INSERT 到系统表 mysql.db,加个 log_% 进去。这不会生效,而且极危险:
-
mysql.db只控制数据库级权限,不支持表级模式匹配 - 手动改系统表可能破坏权限缓存,导致
FLUSH PRIVILEGES失效甚至 mysqld 拒绝启动 - MySQL 8.0+ 的角色权限模型也不支持通配符表名,和旧版本逻辑一致
前缀授权这件事,核心矛盾在于 MySQL 的权限模型设计就是「静态表名 + 动态角色」,没有预留通配符解析入口。真要自动适配新表,只能靠外挂手段兜住,别在权限系统里硬拗。

















