mysql权限模型以'user'@'host'为独立账号,需分别授权;grant后无需flush privileges,仅直改系统表时需要;权限分五层且不继承,同账号多层级权限叠加;生产环境慎用caching_sha2_password认证插件。

MySQL 的权限模型基于「用户+主机+密码」三元组
MySQL 不像 PostgreSQL 那样按数据库用户全局唯一,而是把 'user'@'host' 当作一个独立账号。比如 'app'@'192.168.1.%' 和 'app'@'localhost' 是两个完全无关的账户,权限需分别授予。常见错误是只给远程 IP 授权却忘了 'localhost',导致本地命令行连得上、程序连不上——因为 MySQL 客户端默认用 localhost 连接时走 socket,实际匹配的是 'user'@'localhost',而非 'user'@'%'。
创建用户必须显式指定 host:CREATE USER 'dev'@'10.0.2.%' IDENTIFIED BY 'pwd123';
不写 host 默认是 '%',但这是模糊且不安全的,应避免。
GRANT 语句不自动刷新权限,但 FLUSH PRIVILEGES 多数时候没必要
执行 GRANT 或 CREATE USER 后,权限已写入 mysql.user 等系统表,并由服务端即时加载——不需要手动 FLUSH PRIVILEGES。只有在直接 UPDATE 系统表(如绕过 GRANT 修改 mysql.db)后才需要刷新。
- ✅ 正确做法:
GRANT SELECT ON sales.* TO 'report'@'%'; - ❌ 多余操作:
GRANT ...; FLUSH PRIVILEGES; - ⚠️ 真要用到 FLUSH:仅当你用
UPDATE mysql.user SET authentication_string=...这类直改系统表的操作之后
权限层级混乱是线上事故高发区
MySQL 权限分五层:全局(*)、库级(db.*)、表级(db.tbl)、列级(db.tbl(col1))、存储过程级。低层级权限不会继承高层级,且**同名账号在不同层级的权限是叠加的**。
典型陷阱:
云模块_YunMOK网站管理系统采用PHP+MYSQL为编程语言,搭载自主研发的模块化引擎驱动技术,实现可视化拖拽无技术创建并管理网站!如你所想,无限可能,支持创建任何网站:企业、商城、O2O、门户、论坛、人才等一块儿搞定!永久免费授权,包括商业用途; 默认内置三套免费模板。PC网站+手机网站+适配微信+文章管理+产品管理+SEO优化+组件扩展+NEW Login界面.....目测已经遥遥领先..
- 给
'api'@'%'授予SELECT在shop.users表,又单独给'api'@'%'授予INSERT在shop.orders表——这没问题; - 但如果误对
'api'@'%'执行了REVOKE ALL ON *.* FROM 'api'@'%',会清掉所有全局和库级权限,但**表级、列级权限不受影响**,导致行为不可预测; - 更隐蔽的是:同一账号在
mysql.db和mysql.tables_priv中都有记录时,MySQL 按“最具体匹配”生效,调试需查SHOW GRANTS FOR 'user'@'host';而非只看某张表
生产环境禁用 IDENTIFIED WITH caching_sha2_password 的匿名访问风险
MySQL 8.0 默认认证插件是 caching_sha2_password,它要求 TLS 或安全连接,否则客户端可能静默降级失败。而很多旧脚本或中间件(如某些版本的 Django ORM)未显式配置 ssl_disabled = False,连上去就报 Access denied for user,实际是握手阶段被拒绝,不是权限问题。
解决方式(选其一):
- 创建用户时强制指定旧插件:
CREATE USER 'svc'@'%' IDENTIFIED WITH mysql_native_password BY 'xxx'; - 或在服务端配置
default_authentication_plugin=mysql_native_password(需重启) - 或确保客户端连接串含
?ssl-mode=DISABLED(仅测试环境,勿用于生产)
权限本身没毛病,但认证链断了,SHOW GRANTS 看起来一切正常,排查时容易卡在权限逻辑里绕圈子。









