应显式指定mysql_native_password插件并按表粒度授予SELECT/INSERT/UPDATE等最小必要权限,禁用WITH GRANT OPTION及高危DDL权限,host限定网段如192.168.10.%,密码须符合validate_password策略,授权后需验证SHOW GRANTS及实际操作报错。

直接给普通业务用户最小必要权限,而不是先 GRANT ALL 再删减——这是 MySQL 8.0 权限管理最常踩的坑。
创建用户时必须显式指定认证插件
MySQL 8.0 默认用 caching_sha2_password,但很多旧客户端(如某些 Python MySQL 驱动、Navicat 旧版、PHP mysqli)不支持它,连不上就会报错:Authentication plugin 'caching_sha2_password' cannot be loaded。
所以创建用户时要主动指定 mysql_native_password:
CREATE USER 'appuser'@'192.168.10.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass!2026';
- 别省略
IDENTIFIED WITH mysql_native_password,仅写IDENTIFIED BY会走默认插件 -
host写成网段(如192.168.10.%)比%更安全,也比单 IP 更易维护 - 密码必须含大小写字母、数字、特殊字符;空密码或纯数字会被拒绝(取决于
validate_password策略)
授予权限必须按业务表粒度精确控制
业务用户通常只读写几张表,比如订单系统只需操作 orders 和 order_items。授予 db_name.* 或 *.* 是高危操作,尤其在 MySQL 8.0 中还可能意外获得 SYSTEM_USER 权限,导致 root 都删不掉该用户。
正确做法是逐表授权:
GRANT SELECT, INSERT, UPDATE ON myapp.orders TO 'appuser'@'192.168.10.%'; GRANT SELECT, INSERT ON myapp.order_items TO 'appuser'@'192.168.10.%'; GRANT SELECT ON myapp.products TO 'appuser'@'192.168.10.%';
- 不要用
WITH GRANT OPTION——普通业务用户不需要转授权限 - 不涉及 DDL(如
CREATE TABLE)的操作,就别给ALTER、DROP、INDEX权限 - 如果应用需要
SELECT所有表,优先考虑视图封装,而非开放整个库
权限生效后务必验证实际行为
执行 GRANT 后 MySQL 一般自动生效,但仍有几个隐藏条件会影响结果:
- 用户已存在的连接不会自动继承新权限,需断开重连
- 若之前用同一用户名在不同 host(如
'appuser'@'localhost'和'appuser'@'192.168.10.%')建过多个账号,MySQL 会按 host 匹配优先级选一个,容易误用错账号 - 检查是否真生效:用该用户登录后执行
SHOW GRANTS;,确认输出里只有你明确给的那几条 - 测试失败场景比成功更重要:比如尝试
DELETE FROM orders(没给 DELETE 权),应明确报错ERROR 1142 (42000): DELETE command denied
最容易被忽略的是 host 匹配逻辑——MySQL 把 'appuser'@'%' 和 'appuser'@'192.168.10.%' 当作两个完全独立的账号,权限不共享,删除时也得分别 DROP USER。线上环境建议统一用带网段的 host,避免 localhost 和 % 的语义混淆。


















