创建最小权限账号需先create user再grant,strict模式下漏usage会报错1410;'localhost'仅匹配socket连接,tcp需用ip段;flush privileges非dcl必需;程序连接参数如multi_statements可能触发隐式权限检查失败。

创建最小权限账号时,GRANT 语句漏掉 USAGE 会直接失败
MySQL 5.7+ 默认启用 sql_mode=STRICT_TRANS_TABLES,新建账号不显式赋予 USAGE 权限,后续 GRANT 会报错 ERROR 1410 (42000): You are not allowed to create a user with GRANT。这不是权限不足,而是语法层面被拒绝。
- 必须先用
CREATE USER创建账号(哪怕只是空密码),再GRANT -
GRANT之前不执行CREATE USER,MySQL 会试图在GRANT中隐式建用户——这在 strict 模式下禁用 - 程序账号不需要登录 shell,所以
PASSWORD EXPIRE和ACCOUNT LOCK是安全加分项
正确流程:
CREATE USER 'app_rw'@'10.20.30.%' IDENTIFIED BY 'xxx' PASSWORD EXPIRE ACCOUNT LOCK;<br>GRANT SELECT, INSERT, UPDATE ON `mydb`.* TO 'app_rw'@'10.20.30.%';<br>FLUSH PRIVILEGES;
连接字符串里写死 localhost 却用 TCP 连接,权限永远不生效
MySQL 的 'user'@'host' 中 host 部分区分 Unix socket 和 TCP:当应用通过 127.0.0.1 或具体 IP 连接时,匹配的是 'user'@'%' 或 'user'@'10.20.30.%',不是 'user'@'localhost'。后者只响应本地 socket 连接。
- 确认程序实际连接方式:
netstat -tnp | grep :3306看源 IP 是127.0.0.1还是::1还是真实内网 IP - 避免用
'user'@'localhost'配置程序账号,除非明确走 socket(且程序配置了host=/var/run/mysqld/mysqld.sock) - 如果程序部署在容器或不同机器,
host必须写成具体 IP 段、域名,或谨慎使用%(配合防火墙限制)
FLUSH PRIVILEGES 不是每次改权限都必须执行
只有通过直接操作 mysql.user 等系统表修改权限时,才需要 FLUSH PRIVILEGES;用 CREATE USER/GRANT/DROP USER 这些 DCL 语句,MySQL 自动重载权限缓存。
- 多执行一次
FLUSH PRIVILEGES不报错,但属于冗余操作,可能短暂阻塞其他权限变更 - 自动化脚本里硬编码
FLUSH PRIVILEGES容易掩盖真正问题(比如GRANT本身失败但被忽略) - 验证权限是否生效,用
SHOW GRANTS FOR 'app_rw'@'10.20.30.%';比猜更可靠
非交互式调用要禁用自动重连和多语句,否则权限误判
PHP 的 mysqli 或 Python 的 pymysql 默认开启 autocommit=False 和 multi_statements=True,而程序账号若没授 EXECUTE 或 PROCESS 权限,这类行为可能触发隐式权限检查失败,表现为连接后首条查询就断开。
- 程序连接串显式加参数:
?autocommit=true&multi_statements=false(PDO/MySQLi)或autocommit=True, defer_connect=True(PyMySQL) - 避免在账号上授予
SUPER、PROCESS、FILE等高危权限,它们和“仅供程序调用”目标冲突 - 应用日志里如果出现
Access denied for user ... using password: YES但密码正确,大概率是权限+客户端行为组合导致的静默拒绝
最小权限账号真正的复杂点不在建号动作本身,而在确认程序**实际发起的每个连接细节**——IP、socket、驱动参数、SQL 模式、甚至时区设置,都可能让一条 GRANT 形同虚设。











