首先,数据库名称中包含减号(连字符)这个情况,确实让很多开发者又爱又恨。减号在SQL语言中本身就是减法运算符。当你尝试使用像my-db这样的数据库名时,MySQL的解析器会立刻认为这是“my减去db”,从而抛出语法错误——经典的ERROR 1064 (42000)随即出现。解决这个问题其实非常简单:只需要用反引号将整个数据库名称包裹起来即可。
减号和反引号之间,隐藏着无数MySQL DBA的实战教训。举个例子,如果你直接执行GRANT ALL ON my-db.* TO 'user'@'localhost',那一定会被拒。正确的语法必须是GRANT ALL ON `my-db`.* TO 'user'@'localhost',而且请务必注意:反引号要完整包裹整个数据库名,不能只包一部分,比如my-`db`.*这种写法同样会报错。此外,千万不要一时着急错用成单引号或双引号——那样会被解析成字符串常量,导致权限设置根本不会生效。
不仅如此,今后所有与这个库相关的操作,比如USE、SHOW TABLES IN、DROP DATABASE等,都得记得用反引号包起来。反引号并非可选的装饰,而是MySQL语法中的强制要求。
为包含特殊字符的数据库授权:必须显式指定对象类型
再来谈一个常见的使用误区:即使你只是想授予整个数据库的权限,也一定要写成GRANT ... ON `my-db`.* TO ...,其中的.*绝对不能省略。在MySQL 5.7版本中有一个硬性规定——它不支持裸库名授权,比如直接写ON `my-db`,系统会立刻返回ERROR 1144 (42000):Illegal GRANT/REVOKE command。
GRANT SELECT ON `my-db`.t1 TO ...—— 这是表级授权,写法合法。GRANT EXECUTE ON PROCEDURE `my-db`.p1 TO ...—— 这是存储过程授权,注意必须带上PROCEDURE关键字以及完整的数据库名。如果写成GRANT EXECUTE ON p1或GRANT EXECUTE ON my-db.p1,都会失败。GRANT ALL ON `my-db`.* TO ...—— 这才是唯一能覆盖整个数据库所有对象的授权写法。
用户本身没有WITH GRANT OPTION,无法转授权限
这是一个容易被忽视的权限层级问题。很多真实场景是这样的:你使用普通账号admin去给数据库my-db授权,但当初admin是由root用户通过GRANT ... TO 'admin'@'%'创建的,没有加上WITH GRANT OPTION选项。结果admin去执行GRANT时,立刻报错ERROR 1045 (28000):Access denied。
- 检查方法非常简单:执行
SHOW GRANTS FOR 'admin'@'%',查看输出中是否包含WITH GRANT OPTION。 - 如果缺少该权限,需要由更高权限的账号(通常是root)来补充:
GRANT ALL ON *.* TO 'admin'@'%' WITH GRANT OPTION。 - 特别要注意:即使
admin对`my-db`.*拥有ALL PRIVILEGES,这并不代表它能够转授这些权限——这两个维度是相互独立的。
授权后不生效?别忘了FLUSH PRIVILEGES
MySQL 5.7的权限缓存机制很实在:GRANT命令写入的是内存中的权限结构,但部分客户端工具(比如Navicat、DBeaver这类)可能仍然在使用旧的缓存。后果就是:明明刚授了权,但执行USE `my-db`时依然被拒绝。
- 解决方案:执行
FLUSH PRIVILEGES强制重载权限表,这是最直接且有效的同步手段。 - 注意:如果你使用的是低权限账号来执行
FLUSH PRIVILEGES,会报错——只有具备RELOAD权限的账号才能执行它。root默认拥有该权限,普通管理账号需要额外授予:GRANT RELOAD ON *.* TO 'admin'@'%'。 - 验证授权是否生效的最佳方式:执行
SHOW GRANTS FOR 'target_user'@'host',而不是仅仅依赖客户端界面刷新。
简单总结一下:反引号不是可选项,而是MySQL的强制语法要求;.*不是习惯写法,而是MySQL 5.7版本中的硬性规定;WITH GRANT OPTION和FLUSH PRIVILEGES更不是“试试看”的额外步骤——漏掉其中任何一个,整个授权链都会在某个环节断开。
