Website und Backend liefen, Skript und Cron meldeten keinen Fehler. Unten die Meldungen so, wie MySQL, mysqldump, WordPress und Cron sie geschrieben haben. In den Unterlagen des Kunden ist der Datenbankname durch <datenbank> ersetzt, in der Reproduktion heißt die Shop-Datenbank sklep.
Die genauen Meldungen
Die Backup-Datei des Kunden, 751 B, der ganze Inhalt:
/*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*/ `<datenbank>` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `<datenbank>`;
Die erste Zeile ist die Marke des Sandbox-Modus, die nur der MariaDB-Client schreibt. Den Dump erstellte also mysqldump aus dem Paket mariadb-client auf dem Host (unter Debian 12 ein Link auf mariadb-dump), nicht das Werkzeug aus dem MySQL-Container. Fehlende Kommentare bedeuten --skip-comments, das auch die Endmarke -- Dump completed on … entfernt. Fehlende Schlusszeilen bedeuten, dass der Dump abgebrochen ist: Eine leere Datenbank ergibt eine Datei mit Schlusszeilen (in der Reproduktion 1 173 B).
Das Serverlog des Kunden nach dem Neustart, rund 70 Zeilen in derselben Sekunde:
[ERROR] mysqld: Table './<datenbank>/wp_options' is marked as crashed and should be repaired
[ERROR] mysqld: Table './<datenbank>/wp_postmeta' is marked as crashed and should be repaired
[Warning] Checking table: './<datenbank>/wp_postmeta'
[ERROR] mysqld: Table './<datenbank>/wp_woocommerce_sessions' is marked as crashed and should be repaired
[Warning] Checking table: './<datenbank>/wp_woocommerce_sessions'
Checking table: erscheint nur, wenn myisam-recover-options eingeschaltet ist. Im Image mysql:5.7.44 steht es standardmäßig auf OFF, der Server des Kunden hatte es also in der Konfiguration.
Reproduktion: volle Platte. MyISAM gibt keinen Fehler zurück, sondern wartet auf Platz und hält die Tabellensperre, während die Startseite weiter antwortet:
[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
Neustart des Datenbank-Containers, die typische Reaktion. Docker gibt dem Prozess 10 s, danach 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
Die Sitzungsbereinigung von WooCommerce einige Stunden später:
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
Ab diesem Moment endet jedes erneute Öffnen der Tabelle mit:
ERROR 145 (HY000): Table './sklep/wp_woocommerce_sessions' is marked as crashed and should be repaired
Das Backup aus dem Cron bei beschädigter Tabelle, Ausgabe des alten Skripts:
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)
Die Shop-Datei schrumpfte von 285 757 704 B auf 743 B, mit aktuellem Datum. Mit einem Datenbanknamen in der Länge des Kundennamens ergibt sich exakt 751 B.
Die Beschädigung wirkt wie ein Zünder mit Verzögerung
Nach dem Neustart lief alles, und das Backup mit 285 MB gelang. Die Tabelle bekam die Markierung erst, als die Sitzungsbereinigung von WooCommerce (alle 12 Stunden) auf den inkonsistenten Index traf, und das Öffnen scheiterte erst, nachdem die Tabelle neu geöffnet wurde. Die Backups fallen Stunden oder Tage nach dem Ausfall aus, wenn niemand mehr eine Verbindung herstellt. Den Datenbankprozess nur zu beenden, beschädigte die Tabelle nicht dauerhaft; das schaffte erst die volle Platte mit docker stop, und ein dritter Durchlauf desselben Szenarios endete nur mit einer Warnung. Ob ein Neustart eine Tabelle beschädigt, hängt vom Moment ab.
Wer repariert, was sichtbar ist, lässt den Rest liegen
Im zweiten Durchlauf fiel auch wp_options aus, und der Shop zeigte „Error establishing a database connection“. Das WordPress-Werkzeug wp-admin/maint/repair.php prüft nur 12 Kerntabellen und das, was Plugins über den Filter tables_to_repair ergänzen; WooCommerce ergänzt nichts. Die Website kam zurück, die beschädigte Sitzungstabelle blieb. Dazu meldete das Werkzeug „Failed to repair the wp_options table“, obwohl die Tabelle repariert war: Es liest nur die erste Zeile des Ergebnisses von REPAIR TABLE, status OK steht in der letzten. Auch mysqlcheck --all-databases --check schrieb Corrupt und endete mit Code 0, als Prüfung im Monitoring also wertlos.
Eine Tabelle hält die ganze Datenbank auf, und „Abhilfen“ liefern schlechtere Dateien
Mit dem Standard --lock-tables beginnt der Dump mit einem einzigen LOCK TABLES auf alle Tabellen der Datenbank, eine markierte Tabelle stoppt also alle. Eine Datei mit 743 B fällt auf, wenn jemand auf die Größe schaut. --force liefert 210 MB ohne eine Tabelle und mit normalem Ende, --single-transaction 210 MB, mitten in der Tabellenliste abgeschnitten. Beide sehen aus wie ein Backup. Die Teildatei des neuen Skripts hatte 82 % der Größe des vorigen Backups, hätte also die verbreitete Schwelle „Alarm unter 80 %“ bestanden.
Das Dateidatum beweist nichts, und ein Name ohne Datum zerstört das letzte gute Backup
Die Shell kürzt die Datei bei > <datenbank>.sql, bevor mysqldump überhaupt verbindet. Die Datei hat jede Nacht ein frisches Datum, und die erste missglückte Nacht ersetzt das letzte gute Backup. Die vollständige Version von vor acht Tagen musste aus einer anderen Sicherung des Servers kommen.
Skript und Cron melden Erfolg
mysqldump liefert 2, das Skript 0, weil der letzte Befehl ein echo ist. Die Meldung geht auf stderr, Cron will sie per E-Mail schicken, auf dem Host gibt es keinen Mailserver, also verwirft Cron sie und protokolliert nur END, ohne Exit-Code.
Website und Backend zeigen nichts
Bei beschädigter Sitzungstabelle antworteten Startseite, Shop, Produktseite, Suche, Login und alle geprüften Backend-Seiten mit 200 und ohne Meldung. Das einzige Symptom: Der Gast-Warenkorb hatte nach dem Hinzufügen eines Produkts 0 Positionen. Die einzige Spur im Backend ist WooCommerce, Status, Datenbank, wo die beschädigte Tabelle als fehlend gilt: „Missing base tables: wp_woocommerce_sessions“.
Ein leeres Backup lässt sich „erfolgreich“ einspielen, und Backups können ohne Ausfall versagen
Das Einspielen der Datei mit 743 B endet in jedem geprüften Client mit Code 0 und einer leeren Datenbank: mysql 5.7.44, 8.0.46, 8.4.13 und mariadb 10.11. Die Sandbox-Marke aus der Datei des Kunden (/*M!) stört MySQL-Clients nicht, Dumps aus dem älteren mariadb-dump 10.11.8 beginnen aber mit /*! und spielen nichts ein:
ERROR at line 1: Unknown command '\-'.
Und nach dem Upgrade des Hosts auf Debian 13 (mariadb-client 11.8.6) scheitert dasselbe Skript schon an der Liste der Datenbanken, weil neuere MariaDB-Clients das Serverzertifikat standardmäßig prüfen und MySQL 5.7 ein selbstsigniertes hat. Null Dateien, Code 0, „Kopia zakonczona“:
ERROR 2026 (HY000): TLS/SSL error: Certificate verification failure: The certificate is NOT trusted.