副本集节点间system.users不同步会导致主切后部分节点认证失败(错误码18),因admin.system.users不自动复制;需逐节点比对用户数量、credentials哈希值及roles细节;修复应优先用mongodump/mongorestore同步快照而非重创建;预防须将用户管理纳入自动化部署流程。

副本集节点间 system.users 不同步的典型表现
主节点切换后,新主节点能正常认证,但原主节点(现为从节点)或某个从节点连接时持续报错 Authentication failed (code 18),而用户名密码、authSource 都确认无误。这不是连接字符串或驱动问题,而是用户元数据未在所有节点上一致存在——MongoDB 的用户信息存储在 admin.system.users 集合中,该集合默认不参与复制集的数据同步,必须手动确保各节点内容一致。
如何验证 system.users 是否在所有节点上完全一致
不能只连一次 admin 库查 db.system.users.find() 就完事。需逐个直连每个节点(包括当前主、从、仲裁节点),并比对以下三项:
- 执行
db.system.users.countDocuments({}),确认数量一致 - 对每个用户,检查
db.system.users.findOne({user: "xxx"})返回的credentials字段(尤其是SCRAM-SHA-256或SCRAM-SHA-1对应的digest值)是否完全相同 - 确认
roles数组内容、数据库名(db字段)和角色名(role字段)大小写与拼写完全一致
常见坑:某节点用 db.createUser(..., {roles: [{role: "readWrite", db: "test"}]}) 创建用户,另一节点却漏掉了 db: "test",导致权限对象不等价,认证时被拒绝。
修复不同步:优先用 cloneCollection 而非重新创建用户
直接在从节点上运行 db.createUser() 可能因 pwd 加密方式或盐值差异,生成不兼容的 credentials。更安全的做法是让所有节点共享同一份 system.users 快照:
- 在当前主节点上导出:
mongodump --host rs0/localhost:27017 --db admin --collection system.users -o /tmp/admin_users - 停掉目标从节点的
mongod进程(避免写冲突) - 清空其
admin.system.users:mongorestore --drop --host localhost:27018 /tmp/admin_users - 重启该节点,观察日志中是否出现
Starting up with security.authorization enabled和无auth相关错误
注意:不要对正在运行的副本集成员使用 mongorestore --drop,除非你已暂停其复制(rs.pauseReplication())并确认它不会被选为主。
预防机制:把用户管理纳入部署流程而非临时操作
靠人工同步 system.users 不可持续。真正可靠的方案是将用户创建逻辑固化进初始化脚本:
- 在副本集首次部署时,用
mongo --eval "load('create-users.js')"批量创建所有用户,并显式指定mechanisms: "SCRAM-SHA-256" - 所有后续变更(如加权限、改密码)都通过同一个脚本执行,并在所有节点上顺序运行(可用 Ansible 或 shell 循环 +
mongo --host) - 禁止在生产环境用
mongoshell 交互式创建用户——容易遗漏节点
最易被忽略的一点:副本集配置变更(如新增节点)后,system.users 同步不是自动发生的,必须主动触发验证。哪怕只是换了一台机器重搭从节点,也得把它当成“新节点”走一遍用户导入流程。











