<p>必须为每个库单独执行一条GRANT语句,MySQL不支持合并授权如GRANT SELECT ONdb1.,db2. TO 'user'@'%',语法直接报错ERROR 1064;正确做法是逐条执行,且库名含特殊字符或大小写时必须用反引号包裹。</p>
必须为每个库单独执行一条 GRANT 语句,不能合并或通配“所有目标库”——这是 MySQL 权限模型的硬性规则,不是操作习惯问题。
MySQL 不支持类似 GRANT SELECT ON `db1`.*, `db2`.*, `db3`.* TO 'user'@'%' 这种写法。语法直接报错:ERROR 1064 (42000)。它只接受单库粒度的 ON database.* 结构。
GRANT SELECT ON `db1`.* TO 'app'@'%';、GRANT SELECT ON `db2`.* TO 'app'@'%';、GRANT SELECT ON `db3`.* TO 'app'@'%';
mysql.db 表中“用户+主机+库名”三元组唯一匹配GRANT 必须独立执行并确认返回 OK,不能批量粘贴进客户端一次性运行(部分客户端会静默跳过失败语句)如果库名是 my-app-db、UserDB 或 order_2024_q3,不加反引号就会触发 ERROR 1144 (42000): Wildcard denied for database。
GRANT SELECT ON `my-app-db`.* TO 'app'@'%';,而不是 GRANT SELECT ON my-app-db.* TO ...
`UserDB` 和 `userdb` 是两个不同的库名,大小写敏感性取决于文件系统和 lower_case_table_names 设置,但权限匹配时严格按你写的字符比对% 和 _,例如 GRANT SELECT ON `app_%`.* TO 'dev'@'%' 是合法的;但 GRANT SELECT ON `app%`.*(少下划线)就无效SHOW GRANTS FOR 'app'@'%' 只显示你“执行过哪些 GRANT”,不代表它们都加载成功了。真正有效的权限,得用该用户自己连进去看 CURRENT_USER() 的结果。
mysql -u app -p -h your-host
SHOW GRANTS FOR CURRENT_USER(); —— 注意是 CURRENT_USER(),不是 USER(),后者可能显示连接时用的账号名,而非权限匹配的实际账户GRANT SELECT ON `db1`.* TO 'app'@'%'、GRANT SELECT ON `db2`.* TO 'app'@'%'……缺一条,说明对应那条 GRANT 没成功(常见原因是 Host 不匹配,比如你授的是 'app'@'localhost',但实际连接用的是 'app'@'10.0.1.5')即使 SHOW GRANTS FOR CURRENT_USER() 看起来两条都有,JOIN 仍可能被拒绝。最常忽略的点是:用户连接时的 Host 和你授权时写的 Host 不一致。
SELECT USER(), CURRENT_USER(); —— 前者是“你怎么连的”,后者是“MySQL 认为你是谁”'app'@'192.168.10.22' 和 'app'@'%',说明你授的是 'app'@'%',没问题;但如果输出是 'app'@'192.168.10.22' 和 'app'@'localhost',那就说明 MySQL 匹配到了另一条更精确的记录(比如 'app'@'localhost'),而这条记录没被授予第二个库的权限information_schema 不走 mysql.db 表,跨库 JOIN 用到它时,需要额外显式授权:GRANT SELECT ON `information_schema`.* TO 'app'@'%';
真正麻烦的不是写多少条 GRANT,而是每条背后绑定的“用户@主机+库名”三元组必须严丝合缝。漏一个反引号、错一个 IP 段、少一次 FLUSH PRIVILEGES(虽然 5.7.6+ 后多数情况自动刷新,但某些权限变更仍需手动刷),都会让其中某条权限失效,且很难定位。