Błąd MySQL: Serwer zakończył działanie bez aktualizacji pliku PID — kompletny przewodnik diagnostyki i naprawy
Błąd "The server quit without updating PID file" oznacza, że MySQL zakończył działanie, zanim zdążył zapisać swój identyfikator procesu do skonfigurowanego pliku `.pid` — twarde zatrzymanie uniemożliwiające daemonowi przyjmowanie połączeń. Ten błąd jest niemal zawsze objawem głębszego problemu: błędnej konfiguracji w `my.cnf`, niezgodności uprawnień do katalogu danych, pełnej partycji dyskowej, uszkodzenia na poziomie tabel lub konfliktu portów z drugą instancją MySQL lub MariaDB.
Ten przewodnik omawia każdą potwierdzoną przyczynę źródłową, dostarcza dokładnych poleceń powłoki do diagnozowania i naprawy każdej z nich oraz obejmuje przypadki brzegowe, które ogólne poradniki zazwyczaj pomijają.
Czym jest plik PID i dlaczego jego brak ma znaczenie
MySQL zapisuje swój identyfikator procesu (PID) do małego pliku tekstowego — zazwyczaj `/var/run/mysqld/mysqld.pid` — natychmiast po zainicjowaniu daemona. Systemy init, menedżery usług (systemd, SysVinit) i narzędzia monitorujące odczytują ten plik, aby wysyłać sygnały do właściwego procesu. Jeśli MySQL ulegnie awarii, zakończy działanie nieprawidłowo lub napotka krytyczny błąd podczas uruchamiania, nigdy nie dochodzi do momentu zapisania tego pliku. Menedżer usług zgłasza wtedy komunikat "quit without updating PID file".
Zrozumienie tej sekwencji jest kluczowe: błąd pliku PID jest *konsekwencją*, a nie przyczyną źródłową. Skupianie się na samym pliku PID bez uprzedniego przeczytania dziennika błędów to najczęstszy błąd popełniany przez administratorów.
Typowe przyczyny źródłowe w skrócie
| Przyczyna źródłowa | Typowy objaw w dzienniku błędów | Systemy, których dotyczy |
|---|---|---|
| — | — | — |
| Nieprawidłowa ścieżka `pid-file` w `my.cnf` | `Can't start server: can't create PID file` | Wszystkie dystrybucje |
| Nieprawidłowy właściciel `/var/run/mysqld` | `Permission denied` w katalogu PID | Debian/Ubuntu po aktualizacjach |
| Pełny dysk lub wyczerpanie i-węzłów | `No space left on device` | Każdy serwer z małą partycją `/var` |
| Uszkodzony `ibdata1` lub logi redo InnoDB | `InnoDB: Corruption detected` | MySQL 5.7, 8.0, MariaDB |
| Nieaktualny plik `.pid` po poprzedniej awarii | `A mysqld process already exists` | Każdy system po twardym restarcie |
| Port 3306 jest już zajęty | `Can't start server: Bind on TCP/IP port` | Konfiguracje wieloinstancyjne |
| Odmowa polityki AppArmor lub SELinux | `apparmor="DENIED"` w syslog | Ubuntu, RHEL/CentOS |
| Niezgodny `datadir` po aktualizacji pakietu | `[ERROR] Fatal error: Can't open and lock privilege tables` | Aktualizacje głównych wersji |
Krok 1 — Najpierw przeczytaj dziennik błędów MySQL
Każdy kolejny krok zależy od tego, co mówi dziennik błędów. Nie pomijaj tego kroku.
“`bash
Debian/Ubuntu default path
sudo tail -100 /var/log/mysql/error.log
RHEL/CentOS/AlmaLinux default path
sudo tail -100 /var/log/mysqld.log
If you are unsure of the path, query the running config
mysqld –verbose –help 2>/dev/null | grep "log-error"
“`
Szukaj wierszy zawierających `[ERROR]`, `[FATAL]`, `Aborting` lub `InnoDB`. Pierwszy wpis `[ERROR]` w sekwencji uruchamiania jest niemal zawsze prawdziwą przyczyną.
Krok 2 — Zweryfikuj i napraw katalog pliku PID
Katalog PID jest często odtwarzany jako należący do `root` po restarcie systemu, ponieważ `/var/run` jest montowaniem `tmpfs` w nowoczesnych dystrybucjach Linux. Jest to jedna z najczęściej pomijanych przyczyn w Ubuntu 20.04+ i Debian 11+.
“`bash
Check current ownership
ls -ld /var/run/mysqld
Recreate the directory with correct ownership
sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld
sudo chmod 755 /var/run/mysqld
“`
Aby utrwalić to między restartami w systemach systemd, utwórz regułę `tmpfiles.d`:
“`bash
echo "d /var/run/mysqld 0755 mysql mysql -" | sudo tee /etc/tmpfiles.d/mysqld.conf
“`
Potwierdź, że ścieżka PID skonfigurowana w `my.cnf` odpowiada właśnie utworzonemu katalogowi:
“`bash
sudo grep -i "pid" /etc/mysql/my.cnf /etc/mysql/mysql.conf.d/*.cnf 2>/dev/null
“`
Krok 3 — Sprawdź właściciela i uprawnienia katalogu danych
Katalog danych MySQL musi być w całości własnością systemowego użytkownika `mysql`. Aktualizacje pakietów, ręczne kopiowanie plików lub przywracanie z kopii zapasowej często to psują.
“`bash
Correct ownership recursively
sudo chown -R mysql:mysql /var/lib/mysql
Correct permissions — directories 750, files 640 is more secure than 755/644
sudo find /var/lib/mysql -type d -exec chmod 750 {} ;
sudo find /var/lib/mysql -type f -exec chmod 640 {} ;
“`
Ważny przypadek brzegowy: Jeśli przywróciłeś kopię zapasową używając `rsync` lub `cp` jako `root`, plik gniazda `/var/lib/mysql/mysql.sock` może również należeć do roota. Usuń go — MySQL odtworzy go przy uruchomieniu:
“`bash
sudo rm -f /var/lib/mysql/mysql.sock
sudo rm -f /var/run/mysqld/mysqld.sock
“`
Krok 4 — Sprawdź dostępność miejsca na dysku i i-węzłów
Pełny dysk po cichu uniemożliwia MySQL zapisanie jakiegokolwiek pliku, w tym pliku PID i logów binarnych.
“`bash
Check disk space
df -h
Check inode usage — often overlooked
df -i
Find the largest directories consuming space
sudo du -sh /var/lib/mysql/* | sort -rh | head -20
“`
Jeśli partycja jest pełna, typowymi winowajcami są logi binarne (`mysql-bin.000*`), przypadkowo pozostawione włączone ogólne logi zapytań lub pliki zrzutów pamięci. Aby bezpiecznie wyczyścić stare logi binarne z poziomu MySQL:
“`bash
mysql -u root -p -e "PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 7 DAY);"
“`
Krok 5 — Usuń nieaktualne pliki PID i konfliktujące procesy
Po panice jądra, utracie zasilania lub `kill -9`, na dysku może pozostać nieaktualny plik PID. MySQL odmawia uruchomienia, jeśli go znajdzie.
“`bash
Check for a stale PID file
cat /var/run/mysqld/mysqld.pid
Verify whether that PID is actually running
ps aux | grep mysqld
If the process is not running but the file exists, remove it
sudo rm -f /var/run/mysqld/mysqld.pid
“`
Jeśli inna instancja MySQL lub MariaDB rzeczywiście działa i zajmuje port 3306:
“`bash
sudo ss -tlnp | grep 3306
sudo systemctl stop mariadb
sudo systemctl stop mysql
sudo killall -9 mysqld mysqld_safe
“`
Poczekaj trzy sekundy po zakończeniu procesów przed próbą restartu, aby stany TIME_WAIT gniazda jądra mogły się wyczyścić.
Krok 6 — Sprawdź polityki AppArmor i SELinux
Ta przyczyna jest niemal nigdy nie wspominana w podstawowych poradnikach, a jednak odpowiada za znaczny odsetek błędów pliku PID w systemach Ubuntu i rodziny RHEL.
Ubuntu / AppArmor:
“`bash
sudo dmesg | grep -i apparmor | grep -i mysql
sudo grep -i "DENIED" /var/log/syslog | grep mysql
“`
Jeśli AppArmor blokuje MySQL, zaktualizuj profil lub tymczasowo ustaw go w tryb narzekania do celów diagnostycznych:
“`bash
sudo aa-complain /usr/sbin/mysqld
“`
RHEL / CentOS / AlmaLinux — SELinux:
“`bash
sudo ausearch -c 'mysqld' –raw | audit2why
sudo sealert -a /var/log/audit/audit.log | grep mysqld
“`
Typowa poprawka dla problemów z kontekstem SELinux po przeniesieniu katalogu danych:
“`bash
sudo semanage fcontext -a -t mysqld_db_t "/new/datadir(/.*)?"
sudo restorecon -Rv /new/datadir
“`
Krok 7 — Diagnozuj i naprawiaj uszkodzenia InnoDB
Jeśli dziennik błędów zawiera komunikaty takie jak `InnoDB: Corruption detected`, `[ERROR] InnoDB: Unable to lock ./ibdata1` lub odwołania do niespójności logów redo, przestrzeń tabel InnoDB jest uszkodzona.
W przypadku tabel MyISAM użyj `mysqlcheck`:
“`bash
sudo mysqlcheck –all-databases –repair –user=root –password
“`
W przypadku uszkodzenia InnoDB, `mysqlcheck` jest niewystarczający. Właściwe podejście to włączenie trybu wymuszonego odzyskiwania InnoDB w `my.cnf`:
“`ini
[mysqld]
innodb_force_recovery = 1
“`
Uruchom MySQL z tym ustawieniem, natychmiast zrzuć wszystkie bazy danych, a następnie odbuduj:
“`bash
mysqldump –all-databases –single-transaction -u root -p > full_backup.sql
“`
Zwiększaj `innodb_force_recovery` od 1 do 6 tylko wtedy, gdy niższe wartości nie uruchamiają serwera. Na poziomie 4 i wyżej możliwa jest utrata danych — traktuj instancję jako tylko do odczytu i natychmiast eksportuj dane.
Po pomyślnym zrzucie:
“`bash
sudo systemctl stop mysql
sudo rm -rf /var/lib/mysql/ib_logfile* # Remove corrupt redo logs
Remove innodb_force_recovery from my.cnf
sudo systemctl start mysql
mysql -u root -p < full_backup.sql
“`
Krok 8 — Izoluj błędy konfiguracji w my.cnf
Pojedynczy błąd typograficzny lub nieprawidłowa dyrektywa w `my.cnf` przerwie uruchamianie przed zapisaniem pliku PID. MySQL 8.0+ jest bardziej rygorystyczny w kwestii nieznanych opcji niż wersja 5.7.
“`bash
Validate configuration without starting the server
mysqld –validate-config
Or test with verbose output
mysqld –verbose –help > /dev/null
“`
Wykonaj kopię zapasową i zredukuj konfigurację do wartości domyślnych:
“`bash
sudo cp /etc/mysql/my.cnf /etc/mysql/my.cnf.bak.$(date +%F)
“`
Typowe problematyczne dyrektywy po aktualizacjach głównych wersji obejmują przestarzałe opcje takie jak `query_cache_size`, `query_cache_type`, `innodb_file_format` i `innodb_large_prefix` — wszystkie usunięte w MySQL 8.0.
Krok 9 — Uruchom ponownie MySQL i zweryfikuj
“`bash
sudo systemctl restart mysql
Check service status
sudo systemctl status mysql
Confirm the PID file was written
cat /var/run/mysqld/mysqld.pid
Confirm MySQL is accepting connections
mysqladmin -u root -p status
“`
Krok 10 — Ponowna instalacja MySQL (ostateczność z zachowaniem danych)
Ponowna instalacja powinna nastąpić dopiero po wyczerpaniu wszystkich powyższych kroków diagnostycznych. Przed kontynuowaniem wykonaj kopię zapasową wszystkich danych:
“`bash
If MySQL can start in recovery mode, dump first
mysqldump –all-databases -u root -p > /backup/full_$(date +%F).sql
Copy raw data directory as a secondary backup
sudo rsync -av /var/lib/mysql/ /backup/mysql_datadir_$(date +%F)/
“`
Następnie usuń i zainstaluj ponownie:
“`bash
sudo systemctl stop mysql
sudo apt-get remove –purge mysql-server mysql-client mysql-common
sudo apt-get autoremove && sudo apt-get autoclean
sudo rm -rf /var/lib/mysql /etc/mysql
sudo apt-get install mysql-server
sudo mysql_secure_installation
“`
Przywróć ze zrzutu:
“`bash
mysql -u root -p < /backup/full_$(date +%F).sql
“`
Wybór odpowiedniego środowiska hostingowego, aby zapobiec nawrotom
Wiele z tych awarii — wyczerpanie dysku, resetowanie uprawnień po restartach, rywalizacja o zasoby ze współhostowanymi usługami — to problemy infrastrukturalne w równym stopniu co problemy MySQL. Uruchomienie produkcyjnej bazy danych na odpowiednio skonfigurowanym serwerze z dedykowanymi zasobami eliminuje całe kategorie tych błędów.
Jeśli zarządzasz aplikacją opartą na MySQL, środowisko VPS Hosting zapewnia pełny dostęp root, izolowane zasoby oraz możliwość konfigurowania `tmpfiles.d`, profili AppArmor i nadpisań jednostek systemd bez ograniczeń. W przypadku baz danych o dużym ruchu wymagających gwarantowanych IOPS i RAM, Serwery Dedykowane całkowicie eliminują wszelkie obawy związane z współdzieleniem zasobów.
Dla zespołów preferujących zarządzany panel sterowania zamiast bezpośredniej administracji przez CLI, VPS z cPanel zapewnia interfejsy zarządzania MySQL wraz z dostępem na poziomie serwera. Jeśli Twój stos wymaga również konfiguracji domen i DNS, Rejestracja Domen i Certyfikaty SSL mogą być zarządzane u tego samego dostawcy, zmniejszając nakład pracy operacyjnej.
Macierz decyzyjna: którą poprawkę zastosować jako pierwszą
| Objaw w dzienniku błędów | Pierwsza czynność | Szacowany czas rozwiązania |
|---|---|---|
| — | — | — |
| `Permission denied` w katalogu PID lub danych | Napraw właściciela za pomocą `chown mysql:mysql` | 2 minuty |
| `No space left on device` | Wyczyść logi binarne, rozszerz dysk | 5–30 minut |
| `A mysqld process already exists` | Usuń nieaktualny plik PID, zakończ osierocony proces | 2 minuty |
| `Bind on TCP/IP port: Address already in use` | Zatrzymaj konfliktującą instancję, sprawdź `ss -tlnp` | 5 minut |
| `InnoDB: Corruption detected` | Włącz `innodb_force_recovery`, zrzuć dane, odbuduj | 30 minut do kilku godzin |
| `apparmor="DENIED"` w syslog | Zaktualizuj profil AppArmor lub ustaw tryb narzekania | 10 minut |
| `unknown variable` w dzienniku | Uruchom `mysqld –validate-config`, napraw `my.cnf` | 5 minut |
| Brak konkretnego błędu, wszystko inne zawodzi | Zainstaluj ponownie MySQL, przywróć z kopii zapasowej | 1–2 godziny |
Lista kontrolna kluczowych wniosków technicznych
- Zawsze czytaj `/var/log/mysql/error.log` lub `/var/log/mysqld.log` przed dotknięciem jakiegokolwiek pliku — pierwsza linia `[ERROR]` identyfikuje rzeczywistą przyczynę.
- W systemach systemd z `tmpfs` na `/var/run`, utwórz trwałą regułę `/etc/tmpfiles.d/mysqld.conf`, aby zapobiec resetowaniu uprawnień przy każdym restarcie.
- Po każdym `rsync` lub ręcznym przywróceniu kopii zapasowej, uruchom `chown -R mysql:mysql /var/lib/mysql` przed próbą uruchomienia MySQL.
- Sprawdzaj `df -i` (użycie i-węzłów) obok `df -h` (miejsce na dysku) — pełna tablica i-węzłów daje identyczne objawy jak pełny dysk.
- W przypadku uszkodzenia InnoDB używaj `innodb_force_recovery` stopniowo od 1 wzwyż; nigdy nie przechodź od razu do poziomu 6.
- Weryfikuj składnię `my.cnf` za pomocą `mysqld –validate-config` przed restartem — pozwala to wykryć błędy typograficzne bez nieudanej próby uruchomienia.
- Usuń przestarzałe dyrektywy MySQL 5.7 (`query_cache_*`, `innodb_file_format`) przed aktualizacją do MySQL 8.0.
- W Ubuntu sprawdzaj odmowy AppArmor w `/var/log/syslog`; w RHEL/AlmaLinux sprawdzaj SELinux za pomocą `ausearch -c mysqld`.
Często zadawane pytania
Jaki jest najszybszy sposób na znalezienie przyczyny niepowodzenia uruchomienia MySQL?
Uruchom `sudo tail -50 /var/log/mysql/error.log` i poszukaj pierwszej linii zawierającej `[ERROR]` lub `[FATAL]`. Ta jedna linia identyfikuje przyczynę źródłową w zdecydowanej większości przypadków i określa, którą poprawkę zastosować.
Dlaczego katalog PID traci swoje uprawnienia po restarcie?
W dystrybucjach Linux używających `tmpfs` dla `/var/run` (co obejmuje Ubuntu 18.04+ i Debian 10+), całe drzewo `/var/run` jest odbudowywane w pamięci podczas rozruchu. Każdy katalog niezdefiniowany w `/etc/tmpfiles.d/` jest odtwarzany jako należący do `root:root`. Rozwiązaniem jest dodanie reguły `tmpfiles.d`: `echo "d /var/run/mysqld 0755 mysql mysql -" | sudo tee /etc/tmpfiles.d/mysqld.conf`.
Czy mogę odzyskać dane, jeśli MySQL w ogóle nie uruchamia się z powodu uszkodzenia InnoDB?
Tak, w większości przypadków. Ustaw `innodb_force_recovery = 1` w `my.cnf`, uruchom MySQL i natychmiast uruchom `mysqldump –all-databases`. Jeśli poziom 1 nie uruchamia serwera, zwiększ do 2, potem do 3 i tak dalej. Na poziomach 4–6 część danych może być nieodwracalna, ale większość tabel jest zazwyczaj nienaruszona.
Jak zapobiec ponownemu zatrzymaniu MySQL przez błąd "no space left on device"?
Włącz wygasanie logów binarnych: ustaw `binlog_expire_logs_seconds = 604800` (7 dni) w `my.cnf`. Dodatkowo wyłącz ogólny dziennik zapytań w środowisku produkcyjnym (`general_log = 0`) i skonfiguruj alert użycia dysku przy 80% pojemności w swoim systemie monitorowania.
Czy ten błąd występuje również w MariaDB i czy naprawa jest taka sama?
Tak. MariaDB używa tego samego mechanizmu pliku PID i tej samej struktury katalogu danych co MySQL. Wszystkie kroki diagnostyczne w tym przewodniku mają bezpośrednie zastosowanie do MariaDB, z tą jedyną różnicą, że nazwa usługi to `mariadb` zamiast `mysql` w poleceniach `systemctl`, a dziennik błędów może znajdować się pod adresem `/var/log/mariadb/mariadb.log` w zależności od dystrybucji.
