This post is also available in:
Quando você precisa copiar um usuário de uma instância MongoDB para outra mantendo exatamente as mesmas credenciais, o db.createUser() não resolve. Ele gera um novo hash de senha. A única forma de preservar as credenciais é via inserção direta na coleção system.users. Essa abordagem funciona em qualquer topologia: single instance, replica set ou shard.
Este post documenta o processo completo testado em ambiente de produção.
Por que db.createUser() não funciona aqui
O db.createUser() sempre gera novos hashes SCRAM-SHA-1 e SCRAM-SHA-256 a partir da senha em texto plano. Se você não tem a senha original do usuário de origem, não tem como recriar as credenciais via método convencional.
A alternativa é copiar o documento completo de system.users e inseri-lo diretamente no destino.
Pré-requisito: extrair o usuário na origem
Na instância de origem, conecte e execute:
db.getSiblingDB("admin").system.users.find(
{ user: "db_app_view", db: "admin" }
).toArray()Saída esperada:
[
{
"_id": "admin.db_app_view",
"user": "db_app_view",
"db": "admin",
"credentials": {
"SCRAM-SHA-1": {
"iterationCount": 10000,
"salt": "<SALT_SHA1>",
"storedKey": "<STORED_KEY_SHA1>",
"serverKey": "<SERVER_KEY_SHA1>"
},
"SCRAM-SHA-256": {
"iterationCount": 15000,
"salt": "<SALT_SHA256>",
"storedKey": "<STORED_KEY_SHA256>",
"serverKey": "<SERVER_KEY_SHA256>"
}
},
"roles": [
{ "role": "IPsPermitidos_users", "db": "admin" },
{ "role": "readAnyDatabase", "db": "admin" }
]
}
]Guarde todos os campos de credentials. Eles são os hashes que serão replicados.
Problema: inserção direta é bloqueada por padrão
No destino, uma tentativa de inserir diretamente em system.users retorna:
MongoServerError[Unauthorized]: not authorized on admin to execute command
{ insert: "system.users", ... }Mesmo conectado com o usuário admin, o MongoDB bloqueia escrita direta em coleções de sistema por padrão. O admin tem userAdminAnyDatabase, mas não permissão para bypass de coleções internas.
Solução: conceder __system temporariamente
⚠️ Atenção: A role
__systemconcede acesso irrestrito ao servidor. Conceda apenas pelo tempo necessário para a operação e revogue imediatamente após.
Passo 1: Conceder __system ao usuário admin
use admin
db.grantRolesToUser("admin", [{ role: "__system", db: "admin" }])Saída esperada:
{ "ok": 1 }Passo 2: Inserir o usuário clonado
Substitua os valores de credentials pelos extraídos na origem. Ajuste roles conforme necessário para o destino.
db.getSiblingDB("admin").system.users.insertOne({
_id: "admin.db_app_view",
user: "db_app_view",
db: "admin",
credentials: {
"SCRAM-SHA-1": {
iterationCount: 10000,
salt: "<SALT_SHA1>",
storedKey: "<STORED_KEY_SHA1>",
serverKey: "<SERVER_KEY_SHA1>"
},
"SCRAM-SHA-256": {
iterationCount: 15000,
salt: "<SALT_SHA256>",
storedKey: "<STORED_KEY_SHA256>",
serverKey: "<SERVER_KEY_SHA256>"
}
},
roles: [
{ role: "IPsPermitidos_users", db: "admin" },
{ role: "read", db: "pix" }
]
})Saída esperada:
{ "acknowledged": true, "insertedId": "admin.db_app_view" }💡 Nota: As roles no destino não precisam ser idênticas às da origem. Ajuste conforme o ambiente de destino.
Passo 3: Invalidar o cache de autenticação
db.adminCommand({ invalidateUserCache: 1 })O MongoDB mantém um cache interno de usuários e roles para evitar leituras constantes em system.users. Após uma inserção direta, esse cache não é atualizado automaticamente. O invalidateUserCache força o servidor a reler os dados de autenticação do disco imediatamente, garantindo que o novo usuário seja reconhecido sem necessidade de restart.
Saída esperada:
{ "ok": 1 }Passo 4: Revogar __system
⚠️ Este passo é obrigatório. Não deixe o usuário
admincom a role__systemem produção.
db.revokeRolesFromUser("admin", [{ role: "__system", db: "admin" }])Saída esperada:
{ "ok": 1 }Verificar o resultado
Confirme que o usuário foi criado corretamente:
db.getSiblingDB("admin").system.users.find(
{ user: "db_app_view", db: "admin" }
).toArray()Teste a autenticação com as credenciais originais:
db.auth("db_app_view", "<senha_original>")Checklist rápido
[ ] Extrair documento de system.users na origem
[ ] Conectar ao primary ou instância de destino
[ ] Conceder __system ao admin
[ ] Inserir o documento com insertOne em system.users
[ ] Executar invalidateUserCache
[ ] Revogar __system do admin
[ ] Verificar usuário com find em system.users
[ ] Testar autenticaçãoQuando usar essa abordagem
Este método é necessário quando:
- A senha original não está disponível (apenas o hash)
- Você está migrando usuários entre ambientes sem reset de senha
- Você precisa replicar credenciais exatas (ex: rotação de infra sem impacto na aplicação)
- Você está movendo usuários entre topologias diferentes (ex: single instance para replica set)
Para ambientes onde a senha está disponível, prefira db.createUser() no destino. Inserção direta em system.users deve ser tratada como operação cirúrgica, não rotina.
