mysql中grant语句的_是明确设计的单字符通配符,匹配任意一个字符,不可用反引号或反斜杠转义,唯一安全方案是重命名数据库或对每个含下划线库名单独授权。

MySQL GRANT 语句里 _ 真的会匹配任意单字符库名
不是 bug,是明确设计行为。MySQL 在 GRANT 的数据库名部分(ON db_name.*)中,把 _ 当作通配符处理,和 LIKE 中的语义完全一致:每个 _ 匹配且仅匹配一个任意字符(字母、数字、符号、空格都算)。所以 `db_1`.* 不只给 db_1 授权,还会覆盖 dbA1、db-1、db 1、db%1 等所有第二位是任意字符、第三四位是 1 的库名。
为什么加反引号也拦不住 _ 的通配行为
反引号只解决语法解析问题(比如避免把含 % 的库名当字面量报错),但不关闭通配逻辑。只要没显式转义,_ 就永远是通配符。常见误操作:
- 写成
GRANT SELECT ON `db_1`.* TO 'u'@'%'——_依然生效,不是你想要的“字面下划线” - 以为用双反斜杠
`db\_1`就能转义 —— MySQL GRANT 不支持反斜杠转义_,这会直接报语法错误 - 漏掉反引号却指望
db_1.*被识别为模式 —— 这时 MySQL 把db_1当真实库名查,找不到就报ERROR 1044
想匹配字面意义的下划线库名,只能换命名或改授权方式
MySQL GRANT 层面没有 ESCAPE 子句,也没有方括号转义(如 [ _ ]),所以无法在一条 GRANT 里安全表达“这个 _ 就是下划线字符”。可行路径只有两个:
- 重命名数据库,把
_换成-或__等不参与通配的组合(例如db-1可安全写成`db-1`.*) - 放弃通配,对每个含下划线的真实库名单独授权:
GRANT SELECT ON `db_1`.* TO 'u'@'%'; GRANT SELECT ON `log_2024`.* TO 'u'@'%'; - 如果库名规律性强(如全是
app_xxx_yyy),可改用更窄的通配模式,比如`app\_%\_%`.*不行(GRANT 不支持转义),但`app[a-z0-9]_%`.*也不行(GRANT 不支持字符类)—— 实际上,GRANT 的通配能力比LIKE更弱,只有%和_两种,且无任何转义机制
新增库自动继承权限?别信,得看名字是否命中模式
通配授权是静态匹配,不是运行时监听。比如你执行了 GRANT SELECT ON `project_%`.* TO 'u'@'%',之后新建库 project_v2 会自动有权限;但新建 project_2024_log 也会命中(因为 % 匹配任意长),而 project2024 就不会(缺 _)。最容易被忽略的是:权限是否生效,完全取决于库名字符串是否满足当时那条 GRANT 语句里的模式,跟建库时间无关,也跟库是否存在无关——哪怕库还不存在,授权语句也能成功执行。











