应严格限制数据库权限范围,仅授予具体库如myapp.而非.*;授权前先用create user建用户,撤销权限时需精确匹配原始grant范围,且注意host匹配优先级。

只给数据库级权限,别碰 GRANT ALL ON *.*
直接用 GRANT ALL ON *.* 会把整个 MySQL 实例的控制权交出去,哪怕你后面加了 FLUSH PRIVILEGES 也拦不住。真正限制访问范围,必须从授权对象入手:把 ON 后面的范围写死成 database_name.*,而不是 *.* 或 database_name.table_name(后者是表级,太细;前者是全局,太宽)。
常见错误是复制粘贴时漏改 * ——比如本该写 myapp.*,却写成 *.*,结果用户能 DROP DATABASE otherdb。
- 新建用户后第一件事:先不授任何权限,用
CREATE USER 'u1'@'localhost' IDENTIFIED BY 'pwd'; - 再单独授库级权限:
GRANT SELECT, INSERT, UPDATE ON myapp.* TO 'u1'@'localhost'; - 绝不要在同一条语句里混用
*.*和db.*,MySQL 不报错但权限会叠加生效
CURRENT_USER() 返回值暴露权限配置问题
执行 SELECT CURRENT_USER(); 看到的不是你登录时填的用户名,而是 MySQL 实际匹配到的 'user'@'host' 条目。如果返回 'u1'@'%' 却你以为是 'u1'@'localhost',那很可能你之前用 % 创建过同名用户,而 MySQL 优先匹配更宽泛的 host,导致你授的 localhost 权限根本没生效。
验证方法:SELECT User, Host FROM mysql.user WHERE User = 'u1';,确认只有一条且 Host 匹配你的连接方式。
- 开发环境尽量用
'u1'@'localhost',生产环境若需远程访问,明确指定 IP 段如'u1'@'192.168.1.%' - 删冗余账号用
DROP USER 'u1'@'%';,不是DELETE FROM mysql.user - 改完记得
FLUSH PRIVILEGES;,否则内存缓存的权限不会更新
撤销权限时 REVOKE 必须匹配原始 GRANT 范围
你用 GRANT SELECT ON myapp.* TO 'u1'@'localhost'; 授的权,就不能用 REVOKE SELECT ON *.* FROM 'u1'@'localhost'; 来撤——MySQL 会提示 “There is no such grant defined for user”。权限撤销必须严格对应原始授权范围。
典型误操作:给用户同时授了 myapp.* 和 otherdb.* 权限,想只撤掉一个,却写成 REVOKE ALL ON myapp.*,结果发现 otherdb.* 的权限也被清空了——因为 ALL 是指“当前范围内所有已授予的权限”,不是“所有权限类型”。
- 查用户当前有哪些库级权限:
SHOW GRANTS FOR 'u1'@'localhost'; - 精准撤销某库权限:
REVOKE SELECT, INSERT ON myapp.* FROM 'u1'@'localhost'; - 撤销全部库级权限(保留全局权限):
REVOKE ALL PRIVILEGES ON myapp.* FROM 'u1'@'localhost';
权限生效依赖 host 匹配顺序,% 不是万能通配符
MySQL 检查权限时,按 user 表中 Host 字段的**排序优先级**匹配,不是按你写的顺序。规则是:越具体的 host 值越靠前,'u1'@'127.0.0.1' 优先于 'u1'@'localhost',而 'u1'@'%' 反而是最低优先级。这意味着如果你本地用 mysql -h 127.0.0.1 -u u1 连,即使你只给 'u1'@'localhost' 授了权,也会因 host 不匹配而拒绝访问。
最稳妥的做法:统一用 localhost(Unix socket 连接)或明确指定 IP(TCP 连接),避免依赖 %。
- 确认实际连接用的 host:
SELECT USER(), CURRENT_USER();对比两个函数结果 -
USER()显示你声明的身份,CURRENT_USER()显示 MySQL 实际匹配的账户 - 如果应用必须走 TCP,就别建
'u1'@'localhost',直接建'u1'@'192.168.x.x'并授对应库权限
权限系统底层依赖 mysql.db 表内容,但你不该直接改这张表——GRANT/REVOKE 语句会自动同步并刷新内存缓存;手动改表不触发刷新,极易造成权限状态和实际行为不一致。











