mysql连接密码严禁硬编码,须通过环境变量加载并用os.getenv()获取;grant语句中用户名等标识符需白名单校验,数据查询必须使用%s参数化绑定,禁用字符串拼接。

MySQL连接时密码不能硬编码在connect()参数里
明文写密码进connect()调用是高危操作,一旦代码被泄露或误提交到 Git,数据库就等于裸奔。必须把密码从代码中剥离。
推荐做法是通过环境变量加载:
- Linux/macOS:运行
export MYSQL_PASSWORD="your_strong_pass" - Windows(PowerShell):运行
$env:MYSQL_PASSWORD="your_strong_pass" - Python 中统一用
os.getenv("MYSQL_PASSWORD")获取,配合os.getenv("MYSQL_HOST", "localhost")等做兜底
如果用 pymysql,记得加 charset="utf8mb4";若用 mysql-connector-python,建议显式指定 auth_plugin="caching_sha2_password",避免新版本 MySQL 默认认证插件不兼容导致的 Authentication plugin 'caching_sha2_password' cannot be loaded 错误。
授予权限时不能拼接用户名或库名进GRANT语句
GRANT 是 DCL 语句,MySQL 不支持参数化占位符(如 %s 或 ?),但直接用 Python 字符串格式化拼接用户、数据库、表名会引发 SQL 注入——比如用户名为 admin'@'%' IDENTIFIED BY 'x'; DROP USER 'root'@'%'; -- 就能绕过校验删掉 root。
安全做法只有两个:
- 对输入的用户名、主机名、数据库名做白名单校验:只允许字母、数字、下划线、点、短横线,且长度限制在 32 字符内;用正则
^[a-zA-Z0-9_.-]{1,32}$严格匹配 - 用
mysql.connector的cursor.execute()执行GRANT前,先查mysql.user表确认该用户是否存在,再构造语句——但注意,这个“查表”本身也不能参数化,只能靠白名单过滤后拼接
别信“只要不用 format() 改用 f-string 就安全”这种说法,f-string 同样危险。所有涉及标识符(非数据值)的地方,都必须走白名单,不是“防注入”,是“禁用任意字符串进入 SQL”。
查询/更新数据必须用execute()的参数化模式,不能用%或.format()
这是唯一真正能防注入的数据操作层防护。下面这三种写法,前两种错,第三种对:
# ❌ 错:字符串拼接(哪怕用了 .format 或 f-string)
cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
<h1>❌ 错:% 格式化(MySQL 连接器不识别 %s 占位符的上下文)</h1><p>cursor.execute("SELECT * FROM users WHERE name = '%s'" % name)</p><h1>✅ 对:交给驱动处理绑定参数</h1><p>cursor.execute("SELECT * FROM users WHERE name = %s", (name,))
</p>
关键点:
-
pymysql和mysql-connector-python都支持%s占位符(不是 SQL 标准的?),但值必须以元组或列表传入第二个参数 - 列名、表名、ORDER BY 字段等标识符仍不能参数化,需白名单校验后拼接
- 批量插入用
executemany(),同样只允许数据值参数化,例如executemany("INSERT INTO logs (msg, level) VALUES (%s, %s)", data_list)
权限变更后必须执行FLUSH PRIVILEGES吗?
绝大多数情况下不需要。MySQL 8.0+ 中,GRANT / REVOKE 语句本身就会立即生效,FLUSH PRIVILEGES 只在你手动修改了 mysql.user 等系统表(不推荐)后才需要。
但要注意两个例外:
- 如果你用的是 MySQL 5.7 或更老版本,且使用了
CREATE USER+INSERT INTO mysql.user组合方式建用户(而非标准CREATE USER),那必须FLUSH PRIVILEGES - 某些云数据库(如阿里云 RDS)禁用了
FLUSH PRIVILEGES,执行会报错ERROR 1227 (42501): Access denied,此时应忽略该语句,依赖 GRANT 自身的原子性
所以 Python 脚本里别无脑加 cursor.execute("FLUSH PRIVILEGES"),先判断 MySQL 版本或平台类型,否则可能让自动化流程在云环境上失败。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











