Xử lý sự cố

MySQL hoặc MariaDB không khởi động: thứ tự kiểm tra và phục hồi an toàn

Thứ tự kiểm tra an toàn khi MySQL hoặc MariaDB không khởi động: error log, cấu hình, disk, quyền, port, OOM và tình trạng InnoDB.

MySQL hoặc MariaDB không khởi động
Mục lục

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:

bash
sudo systemctl status mysql
# Hoặc trên MariaDB
sudo systemctl status mariadb

Thô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/FAILURE hay status=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ệnh sudo 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:

bash
sudo journalctl -u mysql -n 50 --no-pager

Bướ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 .err nằ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:

bash
sudo tail -n 50 /var/log/mysql/error.log

Nguyê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 LogBản chất kỹ thuậtHướ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ớiKiể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 deviceHết dung lượng đĩa cứng hoặc cạn kiệt InodeDọ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 ghiKiể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 useCổng 3306 đang bị chiếm dụng bởi một tiến trình khácDù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ệuKiểm tra quyền sở hữu user/group của /var/lib/mysql
[ERROR] InnoDB: Cannot allocate memory for the buffer poolMáy chủ cạn kiệt RAM, không đủ cấp phát cho Buffer PoolGiả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ộtKiên nhẫn chờ đợi, không can thiệp hay restart
[ERROR] InnoDB: Database page corruption on diskBả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 .cnf trong 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_size vố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 .cnf sẽ 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:

bash
# 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-defaults

Nế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:

bash
df -h /var/lib/mysql
df -i /var/lib/mysql

Nế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:

bash
ls -la /var/lib/mysql

Toà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:

bash
sudo chown -R mysql:mysql /var/lib/mysql
sudo chmod 750 /var/lib/mysql

Trá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:

bash
sudo aa-status
# Xem log chặn của AppArmor
sudo dmesg | grep -i apparmor | grep -i mysql

Bướ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:
bash
  sudo ss -tulpn | grep 3306
  • Nếu thấy một tiến trình mysqld cũ 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ằng sudo kill -15 <PID> (gửi tín hiệu SIGTERM để xả dữ liệu xuống đĩa), không dùng kill -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à tmpfs nằ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ủa mysql:mysql:
bash
  sudo mkdir -p /var/run/mysqld
  sudo chown -R mysql:mysql /var/run/mysqld

Bướ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:

text
[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:

text
[ERROR] InnoDB: Database page corruption on disk or a failed read of file

Lú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]:

ini
[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:

bash
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.sql

4. 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_recovery trong 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.sql ngượ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:

  1. 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.
  2. 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;".
  3. Chạy truy vấn thử nghiệm: Thực hiện một câu lệnh SELECT kiể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).
  4. 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/mysql và /var/run/mysqld thuộc về user mysql: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_recovery vớ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

Chia sẻ bài viết hữu ích

Gửi bài viết này cho đồng nghiệp

Đọc tiếp

Bài nên đọc tiếp

Xem tất cả bài về Xử lý sự cố