必须先启用authorization并重启服务,再通过localhost免认证连接admin库创建用户;客户端连接时必须显式指定authsource=admin,否则报unauthorized。

必须先启用 authorization 才能使用 SCRAM-SHA-256
SCRAM-SHA-256 不是独立开关,它依赖 MongoDB 的整体授权系统。没开 authorization: enabled,建再多用户、设再强密码也无效——连接时直接报 Unauthorized 或静默拒绝。
检查配置文件(/etc/mongod.conf 或 mongod.cfg),确认存在且未被注释的段落:
security: authorization: enabled
关键点:
- 不能只
sudo systemctl reload mongod,必须sudo systemctl restart mongod - 重启后执行
mongo --host 127.0.0.1 --port 27017连入,运行db.runCommand({getParameter: 1, authorization: 1}),返回中authorization字段必须为true - Docker 用户注意:
MONGO_INITDB_ROOT_USERNAME等环境变量仅在首次初始化时生效;若容器已运行过,这些变量被忽略,必须手动进 shell 创建用户
第一个用户必须在 admin 库用 localhost 免认证方式创建
启用 authorization: enabled 后,mongod 进入“有授权无用户”状态。此时唯一合法入口是本地回环连接(--host 127.0.0.1 或 Unix socket),不校验凭证。
别用旧版 mongo,推荐用 mongosh:
mongosh --host 127.0.0.1 --port 27017
然后切库并建用户:
use admin
db.createUser({
user: "svc-app",
pwd: "strong_pass_2026",
roles: [{role: "readWrite", db: "myapp"}]
})
常见错误:
- 在
myapp库执行createUser→ 导致后续连接必须配authSource=myapp,但多数驱动默认查admin,连不上 - 用已废弃的
db.addUser()→ 报错或创建出不兼容 SCRAM 的旧格式用户 - 密码含特殊字符(如
@、/)却没 URL 编码 → URI 连接时解析失败,看似认证失败,实为语法错误
客户端连接必须显式指定 authSource=admin
MongoDB 不会默认去 admin 查用户,哪怕用户名叫 admin。不指定 authSource,驱动就按规则找“当前数据库名”作为认证源,大概率错。
URI 示例(Node.js 驱动):
mongodb://svc-app:strong_pass_2026@127.0.0.1:27017/myapp?authSource=admin
代码中显式声明(Go 驱动):
credential := options.Credential{
AuthMechanism: "SCRAM-SHA-256",
AuthSource: "admin",
Username: "svc-app",
Password: "strong_pass_2026",
}
容易忽略的细节:
- 某些老版本驱动(如 Python PyMongo SCRAM-SHA-1,即使服务端支持 SHA-256;必须显式设
authMechanism=SCRAM-SHA-256 - Robo 3T 等 GUI 工具里,“Authentication Database”字段必须填
admin,不能留空或填应用库名 - Spring Boot 的
spring.data.mongodb.authentication-database配置项就是对应authSource,漏配等于白启认证
SCRAM-SHA-256 的密码强度和兼容性边界
SHA-256 本身不防弱口令,它只是让离线爆破更慢。真正起作用的是迭代次数(work factor)和随机 salt——这两项由服务端在 createUser 时自动生成,用户不可控,但可被驱动感知。
生产环境要注意:
- Node.js 驱动最低要求
1.4.29,Python PyMongo 最低2.8;低于这些版本会 fallback 到 SHA-1 或直接报错Unsupported mechanism: SCRAM-SHA-256 - FIPS 模式下,
SCRAM-SHA-1被禁用,必须用SCRAM-SHA-256或MONGODB-X509 - 别混用机制:一个用户只能绑定一种 SCRAM 类型(SHA-1 或 SHA-256),改机制必须删用户重来,
db.updateUser()不能切换哈希算法
最常被跳过的验证环节:连上后执行 db.runCommand({connectionStatus: 1}),看返回里的 authInfo.authenticatedUserRoles 是否非空——这才是认证真正生效的证据,光不报错不算数。











