mysql本身不支持禁止用户改自己密码,因权限模型无password_change_priv等细粒度控制;有效方案是三步封锁:锁定账户、回收create user/alter user等权限、清理外部硬编码密码。

MySQL 本身不支持直接禁止用户改自己密码
想用一条 DENY ALTER USER 或类似语句卡死某个用户的密码修改能力?不行。MySQL 权限模型里压根没有 PASSWORD_CHANGE_PRIV 这类细粒度权限,ALTER USER 和 SET PASSWORD 的执行门槛很低:只要用户拥有 CREATE USER、UPDATE(作用于 mysql 库)或全局 GRANT OPTION 中任意一项,就能成功改密。这不是配置遗漏,是设计如此。
真正有效的三步封锁法
靠单一操作无法堵住所有路径,必须组合出击:
-
ALTER USER 'username'@'host' ACCOUNT LOCK;—— 立即锁账户,后续任何连接都会报ERROR 3118 (HY000): Access denied for user 'username'@'host'. Account is locked. -
REVOKE CREATE USER, ALTER USER, INSERT, UPDATE ON mysql.* FROM 'username'@'host';—— 回收所有可能触发密码变更的权限;注意USAGE无法被REVOKE,别白费劲 -
SHOW GRANTS FOR 'username'@'host';—— 必须确认输出只剩极简权限(如仅SELECT某张业务表),且不含任何对mysql库的操作权
为什么不能只改密码或清空密码字段
这两招看似立竿见影,实则漏洞百出:
-
ALTER USER 'u'@'%' IDENTIFIED BY RANDOM PASSWORD;—— 新密码会返回给客户端,用户仍可登录,接着再执行一次ALTER USER就改回去了 - 手动
UPDATE mysql.user SET authentication_string = ''—— MySQL 8.0+ 直接拒绝空密码;5.7 虽可能允许,但等于主动开后门,比弱密码还危险 - 哪怕你把
authentication_string改成哈希值,也得匹配当前认证插件(如caching_sha2_password),否则下次连接直接报ERROR 1045 (28000),而且 8.0+ 中这类写表操作重启后就丢失
生产环境必须同步清理的外部凭证
数据库内锁死只是第一步,真实风险常藏在应用侧:
- 检查
application.yml、.env等配置文件是否硬编码了该用户的密码——若已泄露,锁账户只是拖延时间 - 确认连接池(如 HikariCP、Druid)未启用自动重连并缓存旧凭证;某些驱动在连接失败时反复重试,会暴露错误细节
- 如果是程序账号(非人用),建议改用
ROLE管理:创建只读角色,授予权限给角色而非用户,后续调整只需动角色,不碰用户本身
账户锁定、权限回收、外部凭证清理——三者缺一不可。少做一步,就可能被绕过。尤其容易忽略的是连接池缓存和配置文件硬编码,它们才是实际攻防中最常被突破的点。











