TL;DR
Bạn gặp lỗi MongoServerError: Authentication failed do sai thông tin đăng nhập, người dùng không tồn tại trong database mong đợi, hoặc thiếu tham số authSource. Cách sửa nhanh nhất:
# Kiểm tra kết nối với authSource tường minh
mongosh "mongodb://username:password@host:27017/mydb?authSource=admin"
Nếu kết nối được, hãy cập nhật connection string và tiếp tục. Nếu không, đọc tiếp bên dưới.
Nguyên nhân gây ra lỗi này
MongoDB xác thực người dùng dựa trên một database cụ thể — gọi là authentication database. Khi thông tin đăng nhập bạn cung cấp không khớp với dữ liệu lưu trữ, bạn sẽ nhận được:
MongoServerError: Authentication failed.
Lỗi này xuất hiện trong mongosh, Node.js (Mongoose/mongodb driver), Python (PyMongo), và bất kỳ MongoDB client nào khác. Nguyên nhân gốc rễ hầu như luôn là một trong những điều sau:
- Sai tên người dùng hoặc mật khẩu
- Người dùng được tạo trong một database khác với nơi bạn đang xác thực
authSourcekhông được chỉ định — mặc định dùng connection database, không phảiadmin- Cơ chế xác thực không khớp (SCRAM-SHA-1 so với SCRAM-SHA-256)
- Người dùng hoàn toàn không tồn tại
Cách 1: Kiểm tra Authentication Database (authSource)
Đây là nguyên nhân số 1 — chiếm phần lớn các lỗi xác thực. Người dùng MongoDB được giới hạn trong database mà họ được tạo ra. Nếu người dùng của bạn nằm trong admin nhưng connection string bỏ qua authSource=admin, MongoDB sẽ tìm kiếm người dùng đó trong database đích thay vào đó. Không tìm thấy, và xác thực thất bại.
# Sai — cố xác thực với 'mydb', không phải 'admin'
mongosh "mongodb://admin:secret@localhost:27017/mydb"
# Đúng — xác thực tường minh với 'admin'
mongosh "mongodb://admin:secret@localhost:27017/mydb?authSource=admin"
Trong Node.js với MongoDB driver:
const client = new MongoClient('mongodb://localhost:27017', {
auth: { username: 'admin', password: 'secret' },
authSource: 'admin',
});
Trong Mongoose:
mongoose.connect('mongodb://localhost:27017/mydb', {
user: 'admin',
pass: 'secret',
authSource: 'admin',
});
Trong PyMongo:
from pymongo import MongoClient
client = MongoClient(
host='localhost',
port=27017,
username='admin',
password='secret',
authSource='admin'
)
Cách 2: Xác nhận người dùng thực sự tồn tại
Trước khi reset mật khẩu, hãy xác nhận người dùng có thực sự tồn tại. Đăng nhập bằng tài khoản admin đã biết và kiểm tra:
# Kết nối với quyền admin trước
mongosh -u root -p --authenticationDatabase admin
# Sau đó chuyển sang database đích và liệt kê người dùng
use mydb
db.getUsers()
# Hoặc kiểm tra tất cả người dùng trong admin
use admin
db.system.users.find({}, { user: 1, db: 1 }).pretty()
Nếu người dùng không có, hãy tạo mới:
use mydb
db.createUser({
user: "appuser",
pwd: "strongpassword",
roles: [{ role: "readWrite", db: "mydb" }]
})
Cách 3: Reset mật khẩu
Người dùng tồn tại nhưng bạn không chắc mật khẩu đúng không? Hãy reset từ phiên admin thay vì đoán mò:
# Kết nối với quyền admin
mongosh -u root -p --authenticationDatabase admin
# Reset mật khẩu
use mydb
db.updateUser("appuser", { pwd: "newstrongpassword" })
Sau đó kiểm tra ngay:
mongosh -u appuser -p newstrongpassword --authenticationDatabase mydb
Cách 4: Kiểm tra cơ chế xác thực
MongoDB 4.0+ mặc định dùng SCRAM-SHA-256, nhưng các driver cũ hoặc cấu hình legacy vẫn có thể dùng SCRAM-SHA-1. Bạn có thể chỉ định cơ chế cụ thể để loại trừ vấn đề này:
# Ép dùng SCRAM-SHA-1 nếu cần
mongosh "mongodb://user:pass@host:27017/db?authSource=admin&authMechanism=SCRAM-SHA-1"
Để kiểm tra cơ chế nào mà người dùng hỗ trợ:
use admin
db.system.users.find({ user: "appuser" }, { mechanisms: 1 })
Nếu mechanisms chỉ hiển thị SCRAM-SHA-1 nhưng driver của bạn yêu cầu SCRAM-SHA-256, hãy cập nhật người dùng để hỗ trợ cả hai:
db.updateUser("appuser", {
pwd: "yourpassword",
mechanisms: ["SCRAM-SHA-1", "SCRAM-SHA-256"]
})
Cách 5: Escape ký tự đặc biệt trong Connection String
Mật khẩu chứa @, :, /, #, hoặc ? sẽ âm thầm phá vỡ việc phân tích connection string nếu không được percent-encode. Trình phân tích URL tách URL tại các ký tự đó trước khi thông tin đăng nhập của bạn đến được MongoDB. Mật khẩu như p@ss:word phải được encode thành p%40ss%3Aword.
# Sai — '@' trong mật khẩu làm vỡ connection string
mongodb://user:p@ss:word@host:27017/db
# Đúng — percent-encode các ký tự đặc biệt
mongodb://user:p%40ss%3Aword@host:27017/db
Trong Node.js, dùng encodeURIComponent() cho mật khẩu trước khi tạo URI. Trong Python, dùng urllib.parse.quote_plus(). Hoặc bỏ qua hoàn toàn thông tin đăng nhập trong URL và truyền chúng dưới dạng tùy chọn driver riêng biệt — cách này hoàn toàn tránh được vấn đề encoding.
Các bước xác minh
Sau bất kỳ sửa chữa nào, hãy xác nhận mọi thứ thực sự hoạt động trước khi triển khai:
# Kiểm tra kết nối trực tiếp
mongosh "mongodb://appuser:password@localhost:27017/mydb?authSource=mydb"
# Chạy query nhanh để xác nhận quyền đọc
db.runCommand({ connectionStatus: 1 })
# Tìm: "authenticated" : true
Để xác minh ở cấp độ ứng dụng, thêm kiểm tra kết nối khi khởi động:
// Node.js
client.connect().then(() => {
return client.db('admin').command({ ping: 1 });
}).then(() => console.log('Xác thực thành công'))
.catch(err => console.error('Xác thực thất bại:', err.message));
Mẹo phòng tránh
Hầu hết các lỗi này có thể tránh được với một vài thói quen nhất quán:
- Luôn chỉ định
authSourcetường minh trong connection string — không bao giờ dựa vào giá trị mặc định. - Lưu thông tin đăng nhập MongoDB trong biến môi trường, không hardcode trong source code.
- Sử dụng mật khẩu mạnh được tạo ngẫu nhiên. Nếu cần, ToolCraft's Password Generator chạy hoàn toàn trên trình duyệt của bạn mà không upload dữ liệu — hữu ích để tạo thông tin đăng nhập mà không bị rò rỉ.
- Ghi chép database nào mỗi người dùng được tạo trong đó. Ba tháng sau, không ai còn nhớ.
- Kiểm tra thông tin đăng nhập ngay sau khi tạo hoặc xoay vòng người dùng — không phải khi đang có sự cố.

