CREATE USER 语句在 MySQL 8.0+ 中必须指定 IDENTIFIED BY(或其它认证方式),否则因 validate_password 插件启用而报错;空密码和 auth_socket 仅限本地调试,生产环境禁用。

CREATE USER 语句必须指定 IDENTIFIED BY 吗?
MySQL 8.0+ 默认启用 validate_password 插件,CREATE USER 时若不带密码,会报错 ERROR 1819 (HY000): Your password does not satisfy the current policy requirements。即使策略宽松,也建议显式设密——空密码或跳过认证(如 auth_socket)仅适用于本地调试,生产环境禁用。
正确写法:
CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'StrongPass!2024';
常见错误:
- 漏写
@'host',导致默认为@'%',权限范围过大 - 用双引号包裹用户名或主机名(MySQL 要求单引号)
- 密码含特殊字符但未用单引号包裹,引发 SQL 解析错误
GRANT 之后为什么 SELECT 还报 Access denied?
权限生效需两步:授权 + 刷新权限缓存。MySQL 不自动重载权限表,GRANT 只写入 mysql.user 等系统表,连接线程仍用旧权限缓存。
必须执行:
FLUSH PRIVILEGES;
但更推荐的做法是:用 GRANT 后直接新建连接验证,而非依赖 FLUSH——因为 GRANT 本身在多数版本中已隐式刷新(MySQL 5.7.6+),FLUSH PRIVILEGES 实际只对手动修改系统表有效。真正容易被忽略的是:
- 用户 host 不匹配:比如创建的是
'app_user'@'192.168.1.%',但应用连的是localhost(等价于127.0.0.1或 Unix socket),需额外授权'app_user'@'localhost' - 权限作用域错误:对库级权限(如
SELECT ON mydb.*)误授给mydb.table1(表级),或漏掉USAGE基础权限
如何最小化授权又满足 Web 应用需求?
Web 应用通常只需 CRUD,禁用 DDL 和管理权限。避免使用 GRANT ALL PRIVILEGES,尤其不要对 * 全局授权。
典型安全授权示例:
GRANT SELECT, INSERT, UPDATE, DELETE ON `myapp_db`.* TO 'app_user'@'192.168.1.%'; GRANT USAGE ON *.* TO 'app_user'@'192.168.1.%';
关键点:
-
USAGE是空权限占位符,允许用户连接但无任何操作权,配合具体库权限使用更清晰 - 数据库名用反引号包裹,防止库名含短横线(如
my-app-db)导致语法错误 - 不授
INDEX、CREATE TEMPORARY TABLES等非必要权限,除非 ORM 明确需要 - 若应用用连接池且复用长连接,改权限后需重启连接池或等待连接超时重建
删除用户后权限还残留?
用 DROP USER 'user'@'host' 才彻底清除用户记录和权限;仅 DELETE FROM mysql.user 不行——权限表之间有关联(如 mysql.db、mysql.tables_priv),手动删会留下脏数据,下次 FLUSH PRIVILEGES 可能报错或行为异常。
安全删除流程:
DROP USER 'app_user'@'192.168.1.%';
验证是否清空:
SELECT User, Host FROM mysql.user WHERE User = 'app_user';
注意:DROP USER 在 MySQL 5.7+ 支持一次删多个,如 DROP USER 'u1'@'h1', 'u2'@'h2';低版本需分多次执行。另外,如果用户正在连接,MySQL 不会阻止删除,但其活跃会话仍保持权限直到断开——这点常被忽视。










