MySQL禁止用户改自己密码需三管齐下:回收CREATE USER权限、锁定账户(ALTER USER ... ACCOUNT LOCK)、清理外部凭证;仅靠REVOKE ALTER USER无效,因该权限不存在。

MySQL 本身不提供禁止用户改自己密码的权限开关,所谓“禁止”只能靠回收能力 + 锁定入口 + 外部清理三者并行,缺一不可。
REVOKE CREATE USER 是关键动作,不是 ALTER USER
很多人执行 REVOKE ALTER USER ON *.* FROM 'u'@'h',结果报错或无效——因为 MySQL 没有 ALTER USER 这个独立权限名。真正起作用的是 CREATE USER 权限,它隐含修改自身认证信息的能力(官方文档明确说明)。只要用户拥有该权限,就能执行 ALTER USER 'u'@'h' IDENTIFIED BY。
- 必须执行:
REVOKE CREATE USER ON *.* FROM 'u'@'h' - 如果用户通过角色获得该权限,仅对用户本体
REVOKE无效,需查mysql.role_edges并对对应角色同步撤销 -
SHOW GRANTS FOR 'u'@'h'执行后,输出里不应再出现CREATE USER或GRANT OPTION
UPDATE ON mysql.user 权限必须精准回收
全局 UPDATE 权限能直写 mysql.user.authentication_string 字段,但回收时容易出错:写成 REVOKE UPDATE ON *.* FROM ... 无效,MySQL 要求精确到库表级。
- 正确写法:
REVOKE UPDATE ON mysql.user FROM 'u'@'h'(不能省略mysql.user) - 注意:MySQL 8.0+ 对
mysql.user表有硬编码保护,即使授了UPDATE,UPDATE mysql.user SET ...也会被拒绝;但CREATE USER权限绕过此限制,所以优先砍它 - 验证是否残留:
SELECT User,Host,Update_priv FROM mysql.user WHERE User='u' AND Host='h',字段值应为N
ACCOUNT LOCK 比改密码更彻底
单纯把密码设成随机值或清空 authentication_string 不安全:前者用户仍可登录并立刻再改回来,后者在 8.0+ 会被拒绝,5.7 则可能启用空密码登录。
- 锁定账户:
ALTER USER 'u'@'h' ACCOUNT LOCK,后续连接直接报ERROR 3118 (HY000): Access denied for user ... Account is locked. - 锁定后,
ALTER USER ... IDENTIFIED BY和SET PASSWORD全部失效,连语法解析都跳过 - 解锁只需:
ALTER USER 'u'@'h' ACCOUNT UNLOCK,无需重置密码
validate_password 插件只校验,不禁止
插件不是权限控制手段,而是强度兜底:它只在 ALTER USER、SET PASSWORD、CREATE USER 时触发校验,失败报 ERROR 1819,但不阻止语句执行本身。
- 设成
LOW策略后,仍需显式执行:SET GLOBAL validate_password_length = 6,否则默认 8 位长度仍会拦住 6 位密码 - 插件对已存在的弱密码完全无感,也不区分用户身份,root 和普通用户一视同仁
- 想绕过?必须先
UNINSTALL PLUGIN validate_password,否则连哈希值直写authentication_string都会被拒绝
最容易被忽略的是应用层硬编码密码和连接池缓存——哪怕数据库里锁死了账户,如果 application.yml 或 HikariCP 配置里还存着旧凭证,运维人员重启服务时就会自动重连成功。账户锁定、权限回收、外部凭证清理,这三件事必须同步做,少一步就等于没做。


















