create user 必须显式指定 host,否则默认为 'localhost',导致远程连接被拒;授权应遵循最小权限原则,禁用 grant option 和 all privileges;mysql 5.7.6+ 不需 flush privileges;8.0+ 默认认证插件可能不兼容旧客户端。

CREATE USER 必须显式指定 host,不能只写用户名
直接执行 CREATE USER 'appuser' IDENTIFIED BY 'pwd123'; 看似合法,但实际等价于 'appuser'@'localhost'。如果应用部署在另一台服务器(比如 IP 是 192.168.5.20),连接时就会报错:Access denied for user 'appuser'@'192.168.5.20'——因为 MySQL 把它当成一个完全不同的账号。
实操建议:
- 先确认应用连接来源:本地开发用
'appuser'@'localhost';生产环境通常用具体 IP 或网段,如'appuser'@'192.168.5.%' - 远程允许要谨慎:
'appuser'@'%'虽方便,但必须配合防火墙或bind-address限制,否则暴露风险高 - 密码必须满足当前
validate_password.policy等级,执行SHOW VARIABLES LIKE 'validate_password%';查策略;测试环境可临时设为LOW,但生产环境应保持MEDIUM或更高
GRANT 之后不用 FLUSH PRIVILEGES(MySQL 5.7.6+)
很多教程还在教执行 FLUSH PRIVILEGES;,这是过时做法。从 MySQL 5.7.6 开始,GRANT 语句本身会自动重载权限缓存,手动刷不仅多余,还可能掩盖真实问题(比如权限没授对,误以为是缓存没刷新)。
唯一需要 FLUSH PRIVILEGES; 的场景是:你绕过 GRANT,直接 INSERT 或 UPDATE 了 mysql.user 表——这种操作本身就不推荐。
实操建议:
- 授权后立刻用新用户测试连接和操作,比如:
mysql -u appuser -p -h 127.0.0.1 -D myproject - 若连不上,优先查
SELECT User, Host FROM mysql.user WHERE User = 'appuser';,确认 host 是否匹配 - 不要依赖
SHOW GRANTS FOR 'appuser'@'192.168.5.%';就认为权限生效——它只显示“被授予的语句”,不反映实际匹配结果
按最小权限原则配 SELECT/INSERT/UPDATE/DELETE,别用 ALL PRIVILEGES
GRANT ALL PRIVILEGES ON myproject.* TO 'appuser'@'192.168.5.%'; 表面省事,实则埋雷。ALL 包含 DROP、ALTER、CREATE VIEW、GRANT OPTION 等高危权限,一旦账号泄露或应用被注入,整个库可能被删或篡改。
实操建议:
- 读写应用只需:
GRANT SELECT, INSERT, UPDATE, DELETE ON myproject.* TO 'appuser'@'192.168.5.%'; - 如果应用用到存储过程或函数,额外加
EXECUTE;若需建临时表,加CREATE TEMPORARY TABLES - 避免跨库访问:
myproject.*比*.*安全得多;更细粒度可到表级,如GRANT SELECT ON myproject.users TO 'appuser'@'192.168.5.%'; - 绝对禁止
GRANT OPTION,否则该用户能再给别人授权,彻底破坏权限边界
MySQL 8.0 默认认证插件不兼容旧客户端
MySQL 8.0+ 默认用 caching_sha2_password 插件,但很多老版本驱动(如 pymysql Authentication plugin 'caching_sha2_password' cannot be loaded。
实操建议:
- 创建用户时就指定兼容插件:
CREATE USER 'appuser'@'192.168.5.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!'; - 已有用户可改:
ALTER USER 'appuser'@'192.168.5.%' IDENTIFIED WITH mysql_native_password BY 'StrongPass123!'; - 改完无需
FLUSH PRIVILEGES,但客户端必须断开重连才生效 - 如果用 Docker 或云数据库,注意镜像或实例默认配置是否已预设插件,避免现场排查
权限系统真正的复杂点不在命令怎么写,而在 host 匹配逻辑和插件兼容性——这两处出错,现象都是“连不上”或“权限拒绝”,但原因完全不同,查日志也看不出区别。动手前先确认 MySQL 版本、客户端驱动版本、连接来源 IP 和当前认证插件,比反复试 GRANT 更省时间。











