You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask应用经SSH隧道连接AWS RDS PostgreSQL报密码认证失败

问题场景

通过本地SSH端口转发将Flask应用连接AWS RDS PostgreSQL实例:

  • 终端执行SSH命令将RDS服务映射至本地1234端口,预期应用连接localhost:1234即可访问目标数据库
  • 完全相同的连接配置在独立Python脚本中运行正常,在Flask应用中连接失败,抛出错误如下:
conn = _connect(dsn, connection_factory=connection_factory, **kwasync)
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "localhost" (::1), port 1234 failed: FATAL:  password authentication failed for user "postgres"
connection to server at "localhost" (::1), port 1234 failed: FATAL:  password authentication failed for user "postgres"
  • 初步怀疑是Flask运行在localhost、同时连接本地转发端口导致的冲突,但二者使用不同端口,无法确认是否为根因。
    使用的连接代码如下:
from sqlalchemy import create_engine, text
from sqlalchemy.ext.automap import automap_base
from sqlalchemy.orm import Session
from sqlalchemy import create_engine, MetaData

Base = automap_base()


engine = create_engine('postgresql+psycopg2://postgres:<pass>\
@localhost:1234/<servername>')


metadata = MetaData()


metadata.reflect(engine)

Base = automap_base(metadata=metadata)
Base.prepare()

session = Session(engine)
排查思路与解决方案

按优先级依次排查以下问题:

  • 优先修复IPv4/IPv6解析差异问题
    错误日志明确显示当前连接的是localhost解析出的IPv6地址::1,绝大多数这类故障都是因为SSH本地转发默认只绑定了IPv4环回地址127.0.0.1,没有监听IPv6环回地址。独立Python脚本运行时默认优先走IPv4解析,Flask的运行环境(内置开发服务器、gunicorn、uWSGI等)通常优先解析IPv6地址,最终连到了没有配置转发规则的IPv6 1234端口——要么该端口无服务直接拒绝连接,要么刚好有其他本地IPv6监听的PostgreSQL服务占用该端口,自然抛出密码认证失败错误。
    修复二选一即可:
    1. 调整SSH转发命令,明确绑定IPv4环回地址,避免IPv6监听歧义:ssh -L 127.0.0.1:1234:<RDS实例内网连接地址>:5432 <跳板机登录用户>@<跳板机地址>
    2. 直接将数据库连接串中的localhost替换为127.0.0.1,强制客户端走IPv4连接,完全绕开主机解析差异,这是成本最低的修复方案:
      engine = create_engine('postgresql+psycopg2://postgres:<pass>@127.0.0.1:1234/<servername>')
      
  • 排查环境变量覆盖问题
    如果启动Flask应用的系统环境中配置了DATABASE_URL、PGPASSWORD、PGHOST这类PostgreSQL连接相关的环境变量,Flask-SQLAlchemy等常用扩展会自动读取这些变量值,覆盖代码中硬编码的连接参数,导致实际使用的密码、连接地址和测试脚本中的配置不一致。可以在Flask应用初始化engine后打印engine.url确认实际生效的连接参数,和测试脚本的参数做比对。
  • 排查连接字符串转义错误
    当前代码中使用反斜杠做字符串换行拼接,反斜杠后如果存在多余空格、缩进对齐错误,会将不可见的空白字符带入密码、主机名字段,直接触发认证失败。不要用反斜杠做长字符串换行,改用括号包裹做隐式字符串拼接最稳妥:
    DB_URI = (
        "postgresql+psycopg2://postgres:<pass>"
        "@127.0.0.1:1234/<servername>"
    )
    engine = create_engine(DB_URI)
    
  • 排查运行用户权限问题
    如果运行独立测试脚本的系统用户和启动Flask应用的用户不是同一个,默认SSH本地转发端口仅允许创建隧道的用户访问,其他用户的访问请求会被拦截,也可能抛出认证类错误。可以统一使用同一个用户启动SSH隧道和Flask应用,或者在SSH转发命令中加-g参数,允许本地所有用户访问该转发端口。

内容的提问来源于stack exchange,提问作者Dr.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:30:46