Cách sửa nhanh trong 30 giây
Nếu bạn cần cấp quyền truy cập cho một IP cụ thể ngay bây giờ, hãy chạy các lệnh sau trên server đang chạy MySQL. Ví dụ này giả định IP máy khách của bạn là 192.168.1.100.
# Đăng nhập cục bộ trên server
mysql -u root -p
# Cấp quyền truy cập (cú pháp MySQL 8.0+)
CREATE USER 'root'@'192.168.1.100' IDENTIFIED BY 'mật_khẩu_bảo_mật_của_bạn';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'192.168.1.100' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Thay 192.168.1.100 bằng địa chỉ IP thực tế của bạn. Bạn có thể sử dụng '%' để cho phép kết nối từ bất kỳ host nào, nhưng việc thực hiện điều đó cho tài khoản root giống như để cửa trước mở toang giữa một thành phố đông đúc.
Tại sao lỗi này xảy ra?
Có thể bạn đã xác nhận mật khẩu chính xác và server đang hoạt động. Tuy nhiên, ngay khi bạn cố gắng kết nối từ DBeaver, TablePlus hoặc một terminal từ xa, MySQL sẽ từ chối. Vấn đề là: MySQL xác định người dùng bằng sự kết hợp giữa Username + Host.
Trong bảng mysql.user, 'admin'@'localhost' là một thực thể hoàn toàn khác với 'admin'@'192.168.1.100'. Theo mặc định, MySQL rất "cẩn trọng". Nó thường chỉ đi kèm với một người dùng root được phép kết nối từ localhost (chính server đó). Nếu IP của bạn không có trong danh sách cho phép, MySQL sẽ từ chối kết nối ngay cả trước khi kiểm tra mật khẩu.
Ba cách để sửa lỗi kết nối
Cách 1: Tạo một người dùng từ xa riêng biệt (Khuyến nghị)
Đừng để lộ tài khoản root. Thay vào đó, hãy tạo một người dùng cụ thể cho ứng dụng hoặc máy dev của bạn. Điều này giúp database của bạn an toàn trong khi vẫn cung cấp quyền truy cập cần thiết.
-- 1. Tạo người dùng cho IP cụ thể của bạn
CREATE USER 'dev_user'@'192.168.1.100' IDENTIFIED BY 'MậtKhẩuỨngDụng_2024!';
-- 2. Chỉ cấp quyền cho database bạn cần
GRANT ALL PRIVILEGES ON ecommerce_db.* TO 'dev_user'@'192.168.1.100';
-- 3. Hoàn tất các thay đổi
FLUSH PRIVILEGES;
Cách 2: Cập nhật người dùng hiện có cho mọi Host
Nếu bạn đang ở trong môi trường phát triển an toàn và muốn một người dùng có thể kết nối bất kể IP của họ là gì, hãy sử dụng ký tự đại diện %. Trên MySQL 8.0 trở lên, hãy sử dụng RENAME USER thay vì cập nhật thủ công các bảng hệ thống.
-- Chuyển host từ 'localhost' sang ký tự đại diện '%'
RENAME USER 'root'@'localhost' TO 'root'@'%';
-- Hoặc tạo một root toàn cầu mới nếu root cục bộ cần được giữ lại
CREATE USER 'root'@'%' IDENTIFIED BY 'MậtKhẩuCủaBạn';
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
FLUSH PRIVILEGES;
Mẹo bảo mật: Nếu bạn cho phép %, hãy đảm bảo tường lửa đám mây của server (như AWS Security Groups) giới hạn cổng 3306 chỉ cho các địa chỉ IP xác định của bạn.
Cách 3: Kiểm tra "bẫy" bind-address
Đôi khi quyền truy cập đã hoàn hảo, nhưng server thậm chí không "lắng nghe" các cuộc gọi từ bên ngoài. Mở file cấu hình MySQL của bạn—thường nằm tại /etc/mysql/mysql.conf.d/mysqld.cnf trên Ubuntu hoặc /etc/my.cnf trên CentOS.
Tìm dòng này:
bind-address = 127.0.0.1
Dòng này yêu cầu MySQL bỏ qua tất cả ngoại trừ lưu lượng truy cập cục bộ. Hãy đổi nó thành 0.0.0.0 để lắng nghe trên tất cả các giao diện mạng, hoặc đặt nó thành IP VPC nội bộ của server.
bind-address = 0.0.0.0
Lưu file và khởi động lại dịch vụ để áp dụng thay đổi:
sudo systemctl restart mysql
Kiểm tra kết nối
Trước khi bạn phải vật lộn với các câu lệnh SQL phức tạp một lần nữa, hãy kiểm tra xem đường truyền mạng có thực sự thông suốt không. Chạy lệnh này từ máy khách cục bộ của bạn:
# Kiểm tra xem cổng 3306 có thể truy cập được không
nc -zv dia_chi_ip_server 3306
Nếu bạn thấy thông báo "Connection to [IP] 3306 port [tcp/mysql] succeeded!", mạng của bạn ổn. Nếu nó hết thời gian chờ (timeout), có khả năng bạn có tường lửa đang chặn đường.
Danh sách kiểm tra lỗi nhanh
- **Tường lửa đám mây:** Bạn đã mở cổng 3306 trong bảng điều khiển AWS, Azure hoặc DigitalOcean chưa?
- **Tường lửa cục bộ:** Kiểm tra `ufw status` hoặc `iptables`. Trên Windows, hãy kiểm tra các quy tắc Advanced Firewall.
- **IP động:** Nếu bạn làm việc tại nhà, IP của bạn có thể thay đổi hàng ngày. Hãy kiểm tra bằng lệnh `SELECT USER();` khi đang kết nối cục bộ để xem chính xác cách MySQL nhận diện host hiện tại của bạn.
- **Docker:** Đối với các container, hãy đảm bảo bạn đã map cổng `3306:3306` và người dùng của bạn được phép kết nối từ subnet bridge của Docker (thường là `172.17.0.0/16`).

