mysql用户权限中使用wildcard字符安全吗_mysql权限匹配规则

来源:这里教程网 时间:2026-02-28 20:49:02 作者:

MySQL库名里用下划线
_
会被当通配符匹配

直接说结论:**不安全,且极易误授权限**。MySQL在解析数据库名时,会把未转义的

_
当作“单字符通配符”,和LIKE语句里的行为一致——这不是bug,是设计如此,但绝大多数人不知道。

比如你执行:

GRANT SELECT ON `db_1`.* TO 'appuser'@'%';

你以为只给了
db_1
库的权限,实际上
db01
dba1
db-1
db?1
……所有第二个字符是任意单字符、结尾是
1
的库,全都被匹配到了。

一个
_
可能扩大权限至 30+ 个意外库(按常见命名字符集估算)
两个
_
(如
db_1_2
)→ 匹配数≈30×30=900,权限失控风险指数级上升
若这些库中混有测试库、备份库或含敏感字段的旧业务库,后果就是越权读取

正确写法:必须用反斜杠
\
转义下划线

MySQL支持用

\
_
%
做字面量转义,这是唯一可靠的方式。

正确授权示例:

GRANT SELECT ON `db\_1`.* TO 'appuser'@'%';

注意:反斜杠在SQL字符串中本身需被MySQL解析,所以命令行或脚本中要写成两个反斜杠
\
(例如Shell中),但在MySQL客户端内直接执行,一个
\
即可生效。

必须用反引号
`
包裹库名,否则转义无效(无引号时
db\_1
会被当成非法标识符报错)
不要依赖“我库名只用字母数字”来侥幸——只要命名规范允许
_
,就存在被误匹配的可能
自动化部署脚本中务必检查所有
GRANT
语句,grep
`.*_.*`
+ 手动验证是否已转义

权限匹配顺序决定“谁说了算”,不是越具体越优先

MySQL权限验证是**从上到下、先到先得**,不是“最精确匹配胜出”。它依次检查:

mysql.user
(全局)→
mysql.db
(库级)→
mysql.tables_priv
(表级)→
mysql.columns_priv
(列级)。一旦某一层找到匹配项(哪怕只是
'%'@'%'
这种宽泛主机),就立即停止向下查。

这意味着:如果用户同时有
SELECT ON *.*
(全局)和
SELECT ON `db\_1`.*
(库级),前者会拦截所有请求,后者完全不生效
撤销权限时,
REVOKE SELECT ON `db\_1`.*
不会影响全局权限;必须显式
REVOKE SELECT ON *.*
才能真正收权
SHOW GRANTS FOR 'user'@'host';
看到的权限列表,是MySQL当前实际生效的组合结果,不是“所有授予过的权限”

生产环境建议:禁用通配符式授权,改用角色+白名单

靠人工盯住每个

_
是否转义,长期来看不可靠。更稳妥的做法是绕过通配符问题本身。

CREATE ROLE
(MySQL 8.0+)定义角色,如
app_reader
,只授明确库名:
GRANT SELECT ON `db_1`.* TO app_reader;
应用账户不直接受权,而是
GRANT app_reader TO 'appuser'@'%';
,后续增删库只需调整角色,不碰用户
旧版本(5.7)可用脚本批量生成严格库名授权语句,避免手写;同时禁止在
GRANT
中出现任何
_
%
字符
CI/CD流水线中加入SQL语法扫描,对含
GRANT.*ON.*`.*_.*`
但无
\_
的语句直接阻断发布

真正麻烦的从来不是记不住转义规则,而是权限条目散落在不同时间、不同人、不同脚本里——等发现

db_prod
db_test
的通配授权意外覆盖时,往往已经晚了。

相关推荐