必须先 CREATE USER,再 GRANT;MySQL 5.7+ 不支持 GRANT 隐式创建用户,否则报错 ERROR 1133,因用户元数据须显式写入 mysql.user 表,且 CREATE USER 才校验密码强度、支持 host 精确控制访问源。

直接给结论:必须先 CREATE USER,再 GRANT,不能靠一条语句“顺手创建并授权”——MySQL 5.7+ 不支持在 GRANT 中隐式建用户(除非启用旧兼容模式,但不推荐)。
为什么不能只用 GRANT 创建用户
早期 MySQL(如 5.1)允许 GRANT ... TO 'user'@'host' IDENTIFIED BY 'pass' 自动建用户,但该行为在 5.7+ 默认禁用。如果直接执行这类语句,会报错:ERROR 1133 (42000): Can't find any matching row in the user table。
这不是权限问题,是语义变更:MySQL 要求用户元数据必须显式写入 mysql.user 表,GRANT 只负责权限赋值。
- 显式建用户更安全、可审计,避免权限和账户生命周期混淆
-
CREATE USER会校验密码强度(若启用 validate_password 插件),GRANT不做这事 - 同一用户名 + 不同 host(如
'app'@'localhost'和'app'@'%')算两个独立账户,必须分别创建
CREATE USER 的 host 写法决定连接来源
host 部分不是可有可无的修饰,它直接控制谁能连进来:
-
'app'@'localhost':仅本机 socket 或 127.0.0.1 TCP 连接可用 -
'app'@'192.168.1.%':匹配整个 C 段内任意 IP -
'app'@'%':允许任意远程 IP 连接(生产慎用,需配合防火墙) - 别写
'app'@'*'—— 这是无效语法,%才是通配符
常见错误:应用部署在 Docker 容器或云主机上,误以为 localhost 能连宿主机 MySQL,实际容器网络里 localhost 指自己,必须用宿主机真实 IP 或 %(并开 3306 端口)。
GRANT 时数据库名要加反引号(尤其含短横线或数字开头)
如果数据库名是 my-app、2024_logs 这类非法标识符(含特殊字符或以数字开头),不加反引号会报错:ERROR 1064 (42000): You have an error in your SQL syntax。
正确写法:
GRANT SELECT, INSERT ON `my-app`.* TO 'app'@'localhost'; GRANT ALL PRIVILEGES ON `2024_logs`.* TO 'logger'@'%';
即使数据库名合法(如 testdb),也建议统一加反引号,避免未来重命名引入风险。
- 权限粒度可精确到表:
GRANT UPDATE ON `mydb`.`users` TO 'admin'@'localhost'; - 不要滥用
ALL PRIVILEGES ON *.*,这等价于把 root 权限交出去 - 授完权必须执行
FLUSH PRIVILEGES;,否则新权限不会生效(缓存未刷新)
远程连接失败?先检查这三处
用户创建和授权都成功,但应用仍连不上,大概率卡在这几个地方:
- MySQL 配置文件(
/etc/mysql/my.cnf或/etc/my.cnf)里bind-address是127.0.0.1,得改成0.0.0.0或具体监听 IP - Linux 防火墙(
ufw或firewalld)没放行 3306 端口 - 云服务商(阿里云/腾讯云)安全组规则没开放 3306 入方向,且源 IP 设置为
0.0.0.0/0或对应段
特别注意:MySQL 用户权限中的 host 和网络层的可达性是两回事。就算你建了 'user'@'%',网络不通照样连不上。


















