必须对用户名和密码分别调用encodeURIComponent()编码,再拼入MongoDB连接字符串;或改用Mongoose的auth选项显式传参,避免URI解析错误。

连接串里密码含 @,Node.js 直接报错 Connection refused 或 Authentication failed
这不是驱动版本或网络问题,而是 URI 解析器在 @ 处截断了字符串。比如密码是 p@ssword,连接串写成 mongodb://user:p@ssword@localhost:27017/db,解析器会把第一个 @ 当作用户名/密码与 host 的分隔符,导致实际尝试用 user:p 认证,后面全被丢弃。
常见错误现象包括:
-
MongoServerSelectionError: getaddrinfo ENOTFOUND p(DNS 尝试解析p为 host) MongoParseError: Invalid connection string-
Authentication failed(但账号密码明明正确)
必须对 username 和 password 单独做 URI 编码,不能只改连接串
直接在连接串里手写 %40 看似可行,但容易漏掉其他字符(如 :、/、=),且不同语言编码规则不一致。Node.js 驱动本身不自动编码用户输入的 credential,必须由你提前处理。
正确做法是用 encodeURIComponent() 分别编码 username 和 password:
const username = 'admin@prod';
const password = 'p@ss:w0rd/123';
const encodedUsername = encodeURIComponent(username);
const encodedPassword = encodeURIComponent(password);
const uri = `mongodb://${encodedUsername}:${encodedPassword}@localhost:27017/mydb`;
注意:
- 不要对整个连接串调用
encodeURIComponent(),会破坏协议前缀和结构 - 不要用
encodeURI(),它不编码/、:等关键分隔符 - 如果用户名或密码为空,
encodeURIComponent('')返回空字符串,没问题
使用 Mongoose 时,绕过 URI 编码的更稳妥方式
Mongoose 支持把认证信息从 URI 中剥离,通过 options 显式传入,彻底避开转义问题:
mongoose.connect('mongodb://localhost:27017/mydb', {
auth: {
username: 'admin@prod',
password: 'p@ss:w0rd/123'
},
authSource: 'admin' // 指定认证数据库,尤其当用户不在 mydb 中时
});
这种写法的好处:
- 完全不用手动转义,字符串原样传递给驱动
- 避免因忘记
authSource导致的Authentication failed(尤其是 Atlas 或启用了 admin-only 用户的部署) - 便于把 credential 从配置文件或环境变量中注入,不拼接字符串
连接串中其他必须转义的字符不止 @
只要出现在 username 或 password 字段里的这些字符,都得转义:
-
@→%40 -
:→%3A -
/→%2F -
?→%3F -
=→%3D -
&→%26
例如密码 pa:ss@w?rd=1&2,完整编码后是 pa%3Ass%40w%3Frd%3D1%262。靠肉眼替换极易出错,所以优先用 encodeURIComponent(),而不是查表硬写。
真正容易被忽略的是:即使你只看到报错提示里有 @,也得检查整个 credential 是否含其他特殊字符——因为只要一个没转,整个连接串就可能被截断或误解析。


















