Người dùng và quyền trong cơ sở dữ liệu
Cách tạo người dùng riêng cho từng ứng dụng trong MySQL và PostgreSQL, cấp quyền tối thiểu và kiểm tra rằng không có gì thừa được cho phép.
Cập nhật 23 tháng 8, 2026
Một ứng dụng chạy dưới quyền root hoặc postgres sẽ giao toàn bộ cơ sở dữ liệu trên máy cho kẻ tấn công ngay từ lỗ hổng đầu tiên. Một người dùng riêng chỉ có quyền trên schema của chính nó sẽ giới hạn thiệt hại trong một dự án.
MySQL và MariaDB
Người dùng ở đây là một cặp “tên và host”, và đây chính là nguồn gốc của sự nhầm lẫn:
CREATE USER 'shop'@'localhost' IDENTIFIED BY 'long-random-password';
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.* TO 'shop'@'localhost';
FLUSH PRIVILEGES;
'shop'@'localhost' và 'shop'@'%' là hai người dùng khác nhau với mật khẩu khác nhau. Đừng tạo bản ghi với host % trừ khi cần thiết: nó cho phép đăng nhập từ bất kỳ địa chỉ nào.
Quyền trên cấu trúc chỉ cần trong quá trình migration:
GRANT CREATE, ALTER, DROP, INDEX, REFERENCES ON shop.* TO 'shop_migrate'@'localhost';
Tách vai trò ứng dụng và vai trò migration là một thực hành tốt: khi đó một truy vấn thông thường về mặt vật lý không thể xóa bảng.
Kiểm tra:
SELECT user, host FROM mysql.user;
SHOW GRANTS FOR 'shop'@'localhost';
Đổi mật khẩu và xóa:
ALTER USER 'shop'@'localhost' IDENTIFIED BY 'new-password';
DROP USER 'shop'@'localhost';
PostgreSQL
Vai trò và các quyền của nó trên cơ sở dữ liệu và schema:
CREATE ROLE shop WITH LOGIN PASSWORD 'long-random-password';
CREATE DATABASE shop OWNER shop;
REVOKE ALL ON DATABASE shop FROM PUBLIC;
Đối với vai trò chỉ đọc (báo cáo, phân tích, bảng điều khiển giám sát):
CREATE ROLE reader WITH LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE shop TO reader;
GRANT USAGE ON SCHEMA public TO reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO reader;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO reader;
Dòng cuối cùng là bắt buộc: nếu không có nó, vai trò sẽ không thấy các bảng được tạo sau khi cấp quyền, và trong một tháng các báo cáo sẽ hỏng trên dữ liệu mới.
Kiểm tra:
\du
\l
\dp
Những gì phải được khóa chặt
- Không có vai trò ứng dụng nào là superuser.
- Mỗi dự án có cơ sở dữ liệu riêng và người dùng riêng.
- Mật khẩu dài và ngẫu nhiên, và khác nhau cho các dự án khác nhau.
- Đăng nhập từ bên ngoài chỉ được phép cho những địa chỉ cần nó — truy cập từ xa.
- MySQL không có người dùng ẩn danh và không có cơ sở dữ liệu test:
mariadb-secure-installationlàm việc này.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân |
|---|---|
Access denied với mật khẩu đúng | Một quy tắc host khác đã khớp, ví dụ ''@'localhost' |
Đã cấp quyền, nhưng SELECT không hoạt động | PostgreSQL thiếu USAGE ON SCHEMA |
| Bảng mới không hiển thị với vai trò | DEFAULT PRIVILEGES chưa được đặt |
| Ứng dụng đã xóa mọi thứ trong một migration thất bại | Vai trò ứng dụng có quyền DROP |
| Mật khẩu hiển thị trong lịch sử lệnh | Đặt mật khẩu từ một tệp, xóa ~/.mysql_history |
Hãy lưu mật khẩu cơ sở dữ liệu trong tệp môi trường của dịch vụ với quyền
600, không lưu trong mã nguồn. Nếu bị xâm phạm, bạn đổi một dòng và khởi động lại, chứ không phải xây dựng lại toàn bộ dự án.