Strona i panel działały, skrypt i cron nie zgłaszały błędu. Poniżej komunikaty tak, jak je zapisały MySQL, mysqldump, WordPress i cron. W materiałach klienta nazwa bazy jest zastąpiona <baza>, w odtworzeniu baza sklepu nazywa się sklep.
Dokładne komunikaty
Plik kopii klienta, 751 B, cała zawartość:
/*M!999999\- enable the sandbox mode */
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/ `<baza>` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `<baza>`;
Pierwsza linia to znacznik trybu sandbox, który dopisuje tylko klient MariaDB, więc zrzut robił mysqldump z pakietu mariadb-client na hoście (na Debianie 12 to dowiązanie do mariadb-dump), a nie narzędzie z kontenera MySQL. Brak komentarzy oznacza --skip-comments, które usuwa też końcowy znacznik -- Dump completed on …. Brak stopki oznacza, że zrzut się przerwał: pusta baza daje plik ze stopką (w odtworzeniu 1 173 B).
Log serwera klienta po restarcie, około 70 linii w tej samej sekundzie:
[ERROR] mysqld: Table './<baza>/wp_options' is marked as crashed and should be repaired
[ERROR] mysqld: Table './<baza>/wp_postmeta' is marked as crashed and should be repaired
[Warning] Checking table: './<baza>/wp_postmeta'
[ERROR] mysqld: Table './<baza>/wp_woocommerce_sessions' is marked as crashed and should be repaired
[Warning] Checking table: './<baza>/wp_woocommerce_sessions'
Checking table: pojawia się tylko przy włączonym myisam-recover-options. W obrazie mysql:5.7.44 domyślnie jest OFF, więc serwer klienta miał to w konfiguracji.
Odtworzenie: pełny dysk. MyISAM nie zwraca błędu, tylko czeka na miejsce i trzyma blokadę tabeli, a strona główna dalej odpowiada:
[ERROR] Disk is full writing './sklep/wp_woocommerce_sessions.MYD' (Errcode: 15795968 - No space left on device). Waiting for someone to free space...
[ERROR] Retry in 60 secs. Message reprinted in 600 secs
Restart kontenera bazy, czyli typowa reakcja. Docker daje procesowi 10 s, potem SIGKILL:
$ docker stop db # 10,5 s, ExitCode 137
[Note] Giving 7 client threads a chance to die gracefully
[Warning] mysqld: Forcing close of thread 31 user: 'sklep'
[ERROR] mysqld: Incorrect key file for table './sklep/wp_woocommerce_sessions.MYI'; try to repair it
[ERROR] Got an error from thread_id=31, .../storage/myisam/mi_write.c:232
Sprzątanie sesji WooCommerce kilka godzin później:
WordPress database error Incorrect key file for table './sklep/wp_woocommerce_sessions.MYI'; try to repair it for query DELETE FROM wp_woocommerce_sessions WHERE session_expiry < 1793638328 ORDER BY session_expiry LIMIT 100 made by ... wc_cleanup_session_data, WC_Session_Handler->cleanup_sessions
Od tej chwili każde ponowne otwarcie tabeli kończy się:
ERROR 145 (HY000): Table './sklep/wp_woocommerce_sessions' is marked as crashed and should be repaired
Kopia z crona przy uszkodzonej tabeli:
Kopia bazy blog
Kopia bazy firma
Kopia bazy sklep
mysqldump: Got error: 145: "Table './sklep/wp_woocommerce_sessions' is marked as crashed and should be repaired" when using LOCK TABLES
Kopia zakonczona: Mon Nov 2 16:53:55 UTC 2026
kod wyjscia skryptu: 0
CRON[107]: (root) CMD ([108] /root/skrypty/backup-mysql.sh)
CRON[107]: (CRON) info (No MTA installed, discarding output)
CRON[107]: (root) END ([108] /root/skrypty/backup-mysql.sh)
Plik sklepu skurczył się z 285 757 704 B do 743 B, z bieżącą datą. Po podstawieniu nazwy bazy o długości jak u klienta wychodzi dokładnie 751 B.
Uszkodzenie działa jak zapalnik z opóźnieniem
Po restarcie wszystko działało, a kopia 285 MB się udała. Tabela dostała flagę dopiero, gdy zadanie sprzątania sesji WooCommerce (co 12 godzin) trafiło na niespójny indeks, a otwarcie zablokowało się dopiero po ponownym otwarciu tabeli. Kopie zaczynają padać godziny albo dni po awarii, gdy nikt już jej z kopiami nie łączy. Samo zabicie procesu bazy nie wystarczyło do trwałego uszkodzenia; zrobił to dopiero pełny dysk z docker stop, a trzeci przebieg tego samego scenariusza skończył się tylko ostrzeżeniem. To, czy restart popsuje tabelę, zależy od chwili.
Naprawa tego, co widać, zostawia resztę
W drugim przebiegu padła też wp_options i sklep pokazał „Error establishing a database connection”. Narzędzie WordPressa wp-admin/maint/repair.php sprawdza tylko 12 tabel rdzenia i to, co wtyczki dopiszą filtrem tables_to_repair; WooCommerce nic nie dopisuje. Strona wróciła, a uszkodzona tabela sesji została. Do tego narzędzie zgłosiło „Failed to repair the wp_options table”, choć tabela była naprawiona: czyta tylko pierwszy wiersz wyniku REPAIR TABLE, a status OK jest w ostatnim. Także mysqlcheck --all-databases --check wypisał Corrupt i zakończył się kodem 0, więc jako test w monitoringu nic by nie dał.
Jedna tabela zatrzymuje całą bazę, a „poprawki” dają gorsze pliki
Przy domyślnym --lock-tables zrzut zaczyna od jednego LOCK TABLES na wszystkie tabele bazy, więc jedna tabela z flagą zatrzymuje wszystkie. Plik 743 B rzuca się w oczy, jeśli ktoś patrzy na rozmiar. --force daje plik 210 MB bez jednej tabeli i z normalnym zakończeniem, --single-transaction plik 210 MB urwany w połowie listy tabel. Oba wyglądają jak kopia. Częściowy plik nowego skryptu miał 82 % rozmiaru poprzedniej kopii, czyli przeszedłby popularny próg „alarm poniżej 80 %”.
Data pliku niczego nie dowodzi, a nazwa bez daty niszczy ostatnią dobrą kopię
Powłoka obcina plik > <baza>.sql, zanim mysqldump się połączy. Plik ma świeżą datę każdej nocy, a pierwsza nieudana noc zastępuje ostatnią dobrą kopię. Pełną wersję sprzed 8 dni trzeba było wziąć z innej kopii serwera.
Skrypt i cron raportują sukces
mysqldump zwraca 2, skrypt 0, bo ostatnie polecenie to echo. Komunikat idzie na stderr, cron próbuje wysłać go pocztą, na hoście nie ma serwera pocztowego, więc go wyrzuca i loguje tylko END, bez kodu wyjścia.
Strona i panel nie pokazują nic
Przy uszkodzonej tabeli sesji strona główna, sklep, karta produktu, wyszukiwarka, logowanie i wszystkie sprawdzone ekrany panelu odpowiadały 200 bez komunikatu. Objaw był jeden: koszyk gościa po dodaniu produktu miał 0 pozycji. Jedyny ślad w panelu to WooCommerce, Status, Baza danych, który uszkodzoną tabelę nazywa brakującą: „Brakujące tabele bazy danych: wp_woocommerce_sessions” (po angielsku „Missing base tables”).
Przywrócenie pustej kopii „się udaje”, a kopie potrafią przestać działać bez awarii
Wczytanie pliku 743 B kończy się kodem 0 i pustą bazą w każdym sprawdzonym kliencie: mysql 5.7.44, 8.0.46, 8.4.13 i mariadb 10.11. Znacznik sandbox z pliku klienta (/*M!) klientom MySQL nie przeszkadza, ale zrzuty ze starszego mariadb-dump 10.11.8 zaczynają się od /*! i nie wczytują nic:
ERROR at line 1: Unknown command '\-'.
A po aktualizacji hosta do Debiana 13 (mariadb-client 11.8.6) ten sam skrypt pada już na liście baz, bo nowsze klienty MariaDB domyślnie weryfikują certyfikat serwera, a MySQL 5.7 ma samopodpisany. Zero plików, kod 0, „Kopia zakonczona”:
ERROR 2026 (HY000): TLS/SSL error: Certificate verification failure: The certificate is NOT trusted.