Khi dịch vụ cơ sở dữ liệu MySQL hoặc MariaDB từ chối khởi động, điều nguy hiểm nhất là liên tục gõ lệnh restart hoặc vội vã làm theo các mẹo trên mạng như xóa tệp tin trong thư mục dữ liệu (/var/lib/mysql). Cơ sở dữ liệu có thể dừng vì một dòng cấu hình sai cú pháp, ổ đĩa bị đầy, quyền thư mục bị đổi, hoặc đang trong tiến trình khôi phục giao dịch sau sự cố (InnoDB crash recovery).
Quy tắc bất biến khi xử lý sự cố database là: đọc chính xác dòng lỗi đầu tiên trong error log trước khi can thiệp, ưu tiên bảo toàn dữ liệu hơn tốc độ phục hồi, và tránh mọi thao tác mang tính phá hủy dữ liệu trong lúc hoảng loạn.
Bước 1: Xem trạng thái systemd nhưng không dừng lại ở chữ failed
Trên các hệ thống Linux hiện đại, bạn thường kiểm tra dịch vụ bằng systemd:
sudo systemctl status mysql
# Hoặc trên MariaDB
sudo systemctl status mariadbThông báo Active: failed chỉ cho biết tiến trình đã dừng hoạt động, hoàn toàn không giải thích nguyên nhân. Hãy chú ý đến:
- Mã thoát (Exit Code): Ví dụ
status=1/FAILUREhaystatus=2. - Dấu hiệu Restart Loop: Nếu dịch vụ liên tục chuyển đổi giữa
activating (auto-restart)vàfailed, systemd đang cố gắng khởi động lại dịch vụ theo chu kỳ nhưng thất bại liên tiếp. Hãy tạm dừng vòng lặp này bằng lệnhsudo systemctl stop mysqlđể bình tĩnh điều tra.
Xem thêm các dòng log khởi động gần nhất trong system journal:
sudo journalctl -u mysql -n 50 --no-pagerBước 2: Tìm và đọc đúng tệp tin Error Log của Database
systemd journal chỉ hiển thị thông báo ở tầng hệ điều hành. Toàn bộ các thông điệp chuyên sâu về tầng lưu trữ InnoDB, nạp bảng dữ liệu, phân quyền và lỗi cú pháp đều được ghi trực tiếp vào tệp error log riêng của database.
Vị trí tệp error log phụ thuộc vào hệ điều hành và cấu hình:
- Trên Ubuntu mặc định:
/var/log/mysql/error.log - Hoặc tệp
.errnằm thẳng trong thư mục dữ liệu:/var/lib/mysql/<hostname>.err
Chạy lệnh trích xuất các dòng lỗi mới nhất:
sudo tail -n 50 /var/log/mysql/error.logNguyên tắc vàng: Luôn tìm đến thông báo lỗi đầu tiên của lần khởi động thất bại gần nhất. Các dòng lỗi theo sau thường chỉ là hệ quả kéo theo của lỗi đầu tiên đó.
Bảng phân loại nhanh nguyên nhân theo thông báo Error Log
| Thông điệp lỗi trong Error Log | Bản chất kỹ thuật | Hướng xử lý ưu tiên | |
|---|---|---|---|
[ERROR] unknown variable '...' | Tham số cấu hình bị sai cú pháp hoặc đã bị loại bỏ ở phiên bản mới | Kiểm tra lại các tệp cấu hình trong /etc/mysql/, xóa hoặc sửa tham số sai | |
[ERROR] Disk is full hoặc No space left on device | Hết dung lượng đĩa cứng hoặc cạn kiệt Inode | Dọn dẹp log, tệp tạm; kiểm tra bằng df -h và df -i | |
[ERROR] Read-only file system | Ổ đĩa bị lỗi phần cứng/hệ thống tệp, kernel tự động khóa ghi | Kiểm tra dmesg; không cố gắng ghi đè dữ liệu | |
[ERROR] Can't start server: Bind on TCP/IP port: Address already in use | Cổng 3306 đang bị chiếm dụng bởi một tiến trình khác | Dùng `ss -tulpn \ | grep 3306` tìm tiến trình đang chiếm cổng |
[ERROR] Can't find file: ... (errno: 13 - Permission denied) | Tiến trình mysql không có quyền đọc/ghi vào thư mục dữ liệu | Kiểm tra quyền sở hữu user/group của /var/lib/mysql | |
[ERROR] InnoDB: Cannot allocate memory for the buffer pool | Máy chủ cạn kiệt RAM, không đủ cấp phát cho Buffer Pool | Giảm innodb_buffer_pool_size, kiểm tra OOM Killer | |
[Note] InnoDB: Starting crash recovery... | Database đang tự động khôi phục dữ liệu sau lần tắt máy đột ngột | Kiên nhẫn chờ đợi, không can thiệp hay restart | |
[ERROR] InnoDB: Database page corruption on disk | Bảng dữ liệu hoặc tệp tin redo log bị hỏng vật lý | Kích hoạt chế độ cứu hộ innodb_force_recovery để dump dữ liệu |
Bước 3: Kiểm tra cấu hình và tham số khởi động
Nếu lỗi xuất hiện ngay sau khi bạn vừa chỉnh sửa file cấu hình hoặc nâng cấp phiên bản MySQL:
- MySQL/MariaDB đọc cấu hình từ nhiều tệp theo thứ tự:
/etc/my.cnf,/etc/mysql/my.cnf, và toàn bộ các tệp.cnftrong thư mục/etc/mysql/conf.d/và/etc/mysql/mysql.conf.d/. - Một tham số cấu hình cũ (ví dụ
query_cache_sizevốn đã bị loại bỏ hoàn toàn từ MySQL 8.0) nếu vẫn còn sót lại trong file.cnfsẽ khiến daemon từ chối khởi động ngay lập tức.
Kiểm tra cú pháp cấu hình trước khi chạy:
# Kiểm tra các giá trị mặc định mà mysqld đọc vào
mysqld --validate-config
# Hoặc trên MariaDB
mariadbd --print-defaultsNếu phát hiện tham số không hợp lệ, hãy mở tệp tương ứng và comment lại bằng dấu #.
Bước 4: Kiểm tra dung lượng đĩa cứng và Inode
Cơ sở dữ liệu đòi hỏi không gian trống liên tục để ghi tệp nhật ký giao dịch (Redo log, Undo log, Binary log) và bảng tạm (temporary table). Khi ổ đĩa chạm ngưỡng 100%, MySQL sẽ tự động dừng khẩn cấp để bảo vệ tính toàn vẹn của dữ liệu.
Kiểm tra dung lượng và số lượng inode:
df -h /var/lib/mysql
df -i /var/lib/mysqlNếu ổ đĩa bị đầy:
- Không tự ý xóa bất kỳ tệp tin nào bên trong
/var/lib/mysql(nhưibdata1,ib_logfile*). - Hãy tìm và dọn dẹp các tệp tin rác ở các thư mục khác: log hệ thống cũ trong
/var/log/, tệp tin tạm trong/tmp/, hoặc các bản sao lưu cũ bị lưu trùng lặp trên ổ đĩa. - Hướng dẫn điều tra chi tiết nằm tại bài VPS đầy ổ đĩa: nguyên nhân, dấu hiệu và cách phòng ngừa.
Sau khi đã giải phóng được ít nhất vài gigabyte dung lượng trống, hãy thử khởi động lại dịch vụ.
Bước 5: Kiểm tra quyền sở hữu thư mục dữ liệu
Daemon MySQL luôn chạy dưới định danh người dùng không đặc quyền là mysql:mysql. Nếu vì một lý do nào đó (như vô tình chạy lệnh restore hoặc chép file bằng tài khoản root), quyền sở hữu của thư mục dữ liệu bị đổi sang root, dịch vụ sẽ báo lỗi Permission denied.
Kiểm tra quyền sở hữu:
ls -la /var/lib/mysqlToàn bộ các thư mục con và tệp tin bên trong phải thuộc về user mysql và group mysql.
Nếu phát hiện bị sai quyền, hãy điều chỉnh lại:
sudo chown -R mysql:mysql /var/lib/mysql
sudo chmod 750 /var/lib/mysqlTránh dùng lệnh chmod 777 lên thư mục cơ sở dữ liệu. Thao tác này vi phạm nguyên tắc an toàn thông tin và có thể khiến MySQL từ chối khởi động do cơ chế kiểm tra quyền nghiêm ngặt.
Ngoài ra, trên Ubuntu, hãy kiểm tra xem hệ thống bảo vệ AppArmor có đang chặn đường dẫn dữ liệu hay không, đặc biệt nếu bạn vừa di chuyển thư mục datadir sang một ổ cứng mount mới:
sudo aa-status
# Xem log chặn của AppArmor
sudo dmesg | grep -i apparmor | grep -i mysqlBước 6: Xử lý xung đột cổng mạng và tệp Socket/PID mồ côi
Nếu log báo lỗi Address already in use trên cổng 3306:
- Kiểm tra xem có một tiến trình MySQL khác đang chạy ngầm mà systemd không quản lý được hay không:
sudo ss -tulpn | grep 3306- Nếu thấy một tiến trình
mysqldcũ vẫn đang lắng nghe, hãy xác định PID của nó và tắt một cách an toàn bằngsudo kill -15 <PID>(gửi tín hiệu SIGTERM để xả dữ liệu xuống đĩa), không dùngkill -9.
Nếu log báo không thể tạo socket (/var/run/mysqld/mysqld.sock):
- Thư mục runtime
/var/run/mysqld(thường làtmpfsnằm trong RAM) có thể bị mất sau khi reboot. Hãy đảm bảo thư mục này tồn tại và thuộc quyền sở hữu củamysql:mysql:
sudo mkdir -p /var/run/mysqld
sudo chown -R mysql:mysql /var/run/mysqldBước 7: Phân biệt giữa Crash Recovery và Hỏng dữ liệu thực sự
Khi máy chủ bị mất điện đột ngột hoặc bị tắt cưỡng bức, ở lần khởi động kế tiếp, engine InnoDB bắt buộc phải thực hiện quy trình Crash Recovery: đọc lại các tệp Redo log để hoàn tất các giao dịch đã commit và rollback các giao dịch đang dở dang.
Nếu bạn mở error log và nhìn thấy các dòng:
[Note] InnoDB: Starting crash recovery...
[Note] InnoDB: Rolled back 120 transactions
[Note] InnoDB: 12864 rollback segments are active.Đây là dấu hiệu hoàn toàn bình thường và lành mạnh. Đối với các cơ sở dữ liệu lớn hàng chục gigabyte, quá trình này có thể mất từ vài phút đến nửa tiếng tùy tốc độ đọc ghi của ổ đĩa.
Trong lúc này, bạn cần kiên nhẫn chờ đợi. Không nên gõ lệnh restart hoặc reboot máy chủ, vì hành động đó sẽ buộc InnoDB phải hủy bỏ quy trình và bắt đầu lại từ con số không, làm tăng nguy cơ hỏng tệp dữ liệu.
Khi nào cần dùng đến innodb_force_recovery?
Chỉ khi quy trình recovery tự động thất bại liên tục, tiến trình MySQL bị crash ngay trong lúc khởi động kèm thông báo lỗi hỏng dữ liệu rõ ràng:
[ERROR] InnoDB: Database page corruption on disk or a failed read of fileLúc này, cơ chế an toàn bình thường không thể mở database. Bạn bắt buộc phải sử dụng tham số cứu hộ khẩn cấp innodb_force_recovery.
Mục đích duy nhất của innodb_force_recovery là đưa database lên ở chế độ chỉ đọc (Read-Only) để bạn kịp thời xuất (dump) toàn bộ dữ liệu ra tệp SQL an toàn, không phải là chế độ để website tiếp tục vận hành kinh doanh.
Quy trình cứu hộ bằng innodb_force_recovery:
1. Sao lưu nguyên trạng thư mục dữ liệu hiện tại: Trước khi can thiệp, hãy tạo một bản sao lưu toàn bộ thư mục /var/lib/mysql sang ổ đĩa khác để giữ nguyên hiện trường đề phòng rủi ro.
2. Bật chế độ cứu hộ ở mức thấp nhất: Mở tệp cấu hình MySQL (/etc/mysql/mysql.conf.d/mysqld.cnf) và thêm dòng sau vào khối [mysqld]:
[mysqld]
innodb_force_recovery = 1(Thang giá trị từ 1 đến 6. Luôn bắt đầu từ mức 1. Chỉ tăng dần lên mức 2, 3 nếu mức thấp hơn không thể khởi động).
3. Khởi động lại dịch vụ và trích xuất dữ liệu:
sudo systemctl start mysql
# Nếu khởi động thành công, lập tức dump toàn bộ dữ liệu ra ngoài
mysqldump -u root -p --all-databases --single-transaction --quick > /backup/recovered_data.sql4. Dựng lại database sạch: Sau khi đã dump dữ liệu an toàn thành công:
- Tắt database, xóa bỏ dòng
innodb_force_recoverytrong file cấu hình. - Khởi tạo một cơ sở dữ liệu hoàn toàn mới và sạch sẽ.
- Import tệp
recovered_data.sqlngược trở lại vào hệ thống.
Nếu hệ thống của bạn đã có bản backup gần nhất hợp lệ theo đúng chiến lược backup cho VPS nhỏ, việc bung lại dữ liệu từ bản sao lưu sạch sẽ thường an toàn và nhanh chóng hơn nhiều so với việc cố gắng chắp vá một database đã bị lỗi vật lý.
Bước 8: Các bước nghiệm thu sau khi Database hoạt động trở lại
Khi lệnh systemctl status mysql báo active (running), hãy thực hiện các bước xác nhận kỹ thuật:
- Kiểm tra error log: Đảm bảo không còn dòng thông báo
[ERROR]nào mới phát sinh. - Kiểm tra kết nối nội bộ: Đăng nhập trực tiếp bằng dòng lệnh:
mysql -u root -p -e "SHOW DATABASES;". - Chạy truy vấn thử nghiệm: Thực hiện một câu lệnh
SELECTkiểm tra số lượng dòng trên các bảng dữ liệu cốt lõi (bảng đơn hàng, bảng người dùng). - Kiểm tra luồng ứng dụng từ bên ngoài: Mở website và thực hiện các thao tác đăng nhập, xem sản phẩm để chắc chắn ứng dụng web đã kết nối và tương tác mượt mà với database.
Checklist kiểm tra an toàn khi MySQL/MariaDB không khởi động
- ☐ Không restart liên tục; đã mở và đọc đúng dòng lỗi đầu tiên trong
/var/log/mysql/error.log. - ☐ Đã kiểm tra dung lượng ổ đĩa (
df -h) và số lượng inode (df -i) trên phân vùng chứa/var/lib/mysql. - ☐ Không xóa các tệp tin hệ thống của InnoDB (
ibdata1, redo log) theo các mẹo trên mạng. - ☐ Đã kiểm tra quyền sở hữu thư mục
/var/lib/mysqlvà/var/run/mysqldthuộc về usermysql:mysql. - ☐ Đã kiểm tra xung đột cổng mạng 3306 bằng lệnh
ss -tulpn. - ☐ Nếu thấy log đang chạy Crash Recovery, kiên nhẫn chờ đợi hoàn tất thay vì ngắt tiến trình.
- ☐ Đã sao lưu nguyên trạng thư mục data trước khi thử nghiệm bất kỳ thao tác phục hồi khẩn cấp nào.
- ☐ Chỉ sử dụng
innodb_force_recoveryvới mục đích duy nhất là dump dữ liệu sang tệp SQL an toàn. - ☐ Đã kiểm thử kết nối và dữ liệu thực tế từ ứng dụng web sau khi phục hồi.
Cơ sở dữ liệu là trái tim chứa đựng toàn bộ tài sản thông tin của doanh nghiệp. Tiếp cận sự cố database bằng sự cẩn trọng, kỷ luật và tuân thủ chặt chẽ thông điệp từ nhật ký lỗi là cách duy nhất để bảo vệ an toàn cho dữ liệu của bạn. Nếu database dừng đột ngột trong lúc website đang đón nhận khách hàng, hãy bình tĩnh áp dụng Quy trình 30 phút đầu khi website gặp sự cố để vừa giữ được hiện trạng log vừa điều phối hạ nhiệt dịch vụ đúng trình tự.
Nguồn tham khảo
- MySQL 8.4 Reference Manual — Starting and Stopping the Server
- MySQL 8.4 Reference Manual — InnoDB Troubleshooting & Recovery
- MySQL 8.4 Reference Manual — Forcing InnoDB Recovery
- MariaDB Documentation — What to Do if MariaDB Doesn't Start
- Percona Database Performance Blog — Dealing with Corrupted InnoDB Tables



