
当数据库密码包含特殊字符(如 @)时,sqlalchemy 的连接字符串会将其误识别为 url 中的用户名/主机分隔符,从而引发 `getaddrinfo failed` 等连接异常;正确做法是使用 `urllib.parse.quote_plus()` 对密码进行 url 编码。
在使用 SQLAlchemy(配合 PyMySQL 或 MySQLdb)构建 MySQL 连接字符串时,格式通常为:
mysql+pymysql://
该格式严格遵循 URL 规范,因此所有特殊字符(尤其是 @、/、:、?、# 等)都必须进行百分号编码(URL-encoding),否则解析器会错误截断凭证信息。例如,密码 Gspann@123 中的 @ 会被误认为是用户与主机之间的分隔符,导致主机地址被解析为 Gspann@123@35.187.158.251,最终触发 Can't connect to MySQL server on 'Gspann@123@35.187.158.251' 类似错误。
✅ 正确解决方案:对密码(及用户名,如含特殊字符)调用 urllib.parse.quote_plus() 进行编码:
from urllib.parse import quote_plus
from sqlalchemy import create_engine
import pandas as pd
# 安全编码密码(自动处理 @ / : 等字符)
password = "Gspann@123"
encoded_password = quote_plus(password)
db_connection_str = f"mysql+pymysql://beat_dq_readonly:{encoded_password}@35.187.158.251/beat_results_dev"
# 创建引擎(建议添加 pool_pre_ping=True 提升健壮性)
db_connection = create_engine(db_connection_str, pool_pre_ping=True)
# 执行查询
df = pd.read_sql("SELECT * FROM vw_dv_count_rpt", con=db_connection)
print(df.head())⚠️ 注意事项:
- 不要手动替换 @ 为 %40 —— quote_plus() 比 quote() 更适合密码场景(它将空格转为 +,且编码更全面);
- 若用户名也含特殊字符(如 user@domain),同样需编码;
- 生产环境请避免硬编码密码,推荐使用环境变量(如 os.getenv("DB_PASSWORD"))或密钥管理服务;
- 首次连接失败时,可加 echo=True 参数(create_engine(..., echo=True))查看实际生成的连接 URL,辅助调试。
总结:URL 中的认证信息必须严格符合 RFC 3986 规范。只要涉及非字母数字字符,就应通过 quote_plus() 编码——这是 SQLAlchemy 连接 MySQL / PostgreSQL 等数据库时保障连接字符串鲁棒性的关键实践。










