Upgrade von MySQL 5.7 auf MySQL 8, Probleme und Fehler

Damit eine Website – so wie diese hier – im Internet erreichbar ist, ist natürlich ein Webserver nötig. Und gelegentlich muss so ein Webserver gewartet werden, die Software muss aktualisiert werden etc. Bei meinem Upgrade bin ich gleich auf einen neuen dedizierten Server umgestiegen und musste diesen komplett neu einrichten. Dabei bin ich auch von MySQL 5.7 auf MySQL 8 umgestiegen. Leider brachte der Umstieg einige Probleme mit sich. Die Probleme waren so gravierend, dass ich mich dazu entschieden habe, diese hier festzuhalten und meinen Lösungsansatz zu zeigen.

MySQL Upgrade mit mysqldump –all-databases

Zunächst habe ich alle Datenbanken des Servers mit mysqldump exportiert. Mit der –all-databases Option werden alle Datenbanken in ein Dump geschrieben. Auch die interne MySQL Datenbank, die unter anderem auch die Zugangsdaten aller Benutzer enthält. Und bisher war es in der Regel immer möglich, den Dump direkt auf einem neuen Server einzuspielen und alles hat direkt funktioniert.

# alter Server
mysqldump --all-databases -p > dump.sql


# neuer Server
mysql < dump.sql

# bzw. wenn bereits ein root Kennwort gesetzt ist
mysql -p < dump.sql

Das Einspielen des Dumps hat allerdings leider nicht funktioniert. Es kam folgender Fehler:

ERROR 3554 (HY000) at line 318: Access to system table 'mysql.innodb_index_stats' is rejected.

Also wohl Probleme mit den Rechten.

Bei der Suche nach einer Lösung bin ich auf den Tipp gekommen, das Einspielen des MySQL Dumps zu forcen. Dafür gibt es die Option -f. Ich habe es gemacht, allerdings war das Resultat weniger gut. Die Datenbanken wurden eingespielt, offensichtlich auch die User und Zugriffsrechte (GRANT), allerdings wohl im falschen Datenbanken-Typ.

mysql -f < dump.sql
ERROR 3554 (HY000) at line 318: Access to system table 'mysql.innodb_index_stats' is rejected.
ERROR 3554 (HY000) at line 321: Access to system table 'mysql.innodb_index_stats' is rejected.
ERROR 3554 (HY000) at line 338: Access to system table 'mysql.innodb_index_stats' is rejected.
ERROR 1062 (23000) at line 341: Duplicate entry 'sys-sys_config-PRIMARY-n_diff_pfx01' for key 'innodb_index_stats.PRIMARY'
ERROR 3554 (HY000) at line 349: Access to system table 'mysql.innodb_table_stats' is rejected.
ERROR 3554 (HY000) at line 352: Access to system table 'mysql.innodb_table_stats' is rejected.
ERROR 3554 (HY000) at line 367: Access to system table 'mysql.innodb_table_stats' is rejected.
ERROR 1062 (23000) at line 369: Duplicate entry 'sys-sys_config' for key 'innodb_table_stats.PRIMARY'

 Das hatte Auswirkungen auf einige Seiten. Zum Beispiel auf die Wordpress Admin Seite. Es kam dann die Fehlermeldung:

Uncaught mysqli_sql_exception: View 'information_schema.COLUMNS' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them in /media/ramdisk/****/wp-includes/wp-db.php:2056

Die Lösung wäre hier wohl den mysql.infoschema User anzulegen, doch auch das scheiterte:

mysql> create user 'mysql.infoschema'@'localhost' identified by 'password';
ERROR 1726 (HY000): Storage engine 'MyISAM' does not support system tables. [mysql.user]

Tipps, wie ein Update bzw. Upgrade über mysql durchführen zu lassen, haben leider auch nicht funktioniert.

mysqld --upgrade=FORCE

Meine Lösung des Problems beim Upgrade von MySQL 5.7 auf 8

Ich saß sicher eine Stunde und habe Lösungen herumprobiert. Danach war Schluss mit Lustig. Denn die ganzen Websites waren auch down. Ich wusste nicht, was das Einspielen des Dumps noch für Probleme ausgelöst haben könnte. Ich musste deshalb neu beginnen und irgendwie die Datenbanken und die User-Berechtigungen übertragen. Das habe ich in den folgenden Schritten erledigt.

Alles sauber machen

Ich hatte keine Lust mehr, mehr Zeit in die Fehlersuche zu investieren. Deshalb habe ich die Datenbank heruntergefahren, habe dann die defekten Datenbanken gelöscht (bzw. verschoben) und MySQL neu initialisiert.

# MySQL stoppen
systemctl stop mysql

# Verzeichnis mit Datenbanken umbenennen, damit MySQL es nicht mehr findet
mv /var/lib/mysql /var/lib/mysql_broken

# leeres neues Verzeichnis erstellen
mkdir /var/lib/mysql

# Rechte setzen
chown mysql:mysql /var/lib/mysql

# Datenbank initialisieren
mysqld --initialize

Danach habe ich festgestellt, dass der root user mit einem Passwort gesichert ist. Dieses Passwort steht in der Log-Datei von MySQL und muss möglichst sofort geändert werden.

less /var/log/mysql/error.log

# in less kann man mit der > Taste ganz nach unten springen und mit q verlassen.

[Note] [MY-010454] [Server] A temporary password is generated for root@localhost: y>)r,;lwy3jA

mysql -p     #mit dem Passwort oben einloggen

# Passwort für den User root ändern.
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';

mysqldump ohne die mysql Datenbank

MySQL legt alles, was für den Betrieb der Datenbanken notwendig ist, in der Tabelle mysql ab. Deshalb war der nächste Schritt, einen Dump zu erstellen, der diese Datenbank exkludiert. 

Ich weiß leider nicht wieso, aber bis heute gibt es für MySQL Dump keinen –exclude Parameter. Ich habe deshalb folgendes Script gefunden. Achtung, bitte das Root Passwort oben ändern.

MYSQL_USER=root
MYSQL_PASS=rootpassword
MYSQL_CONN="-u${MYSQL_USER} -p${MYSQL_PASS}"
#
# Collect all database names except for
# mysql, information_schema, and performance_schema
#
SQL="SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN"
SQL="${SQL} ('mysql','information_schema','performance_schema')"

DBLISTFILE=/tmp/DatabasesToDump.txt
mysql ${MYSQL_CONN} -ANe"${SQL}" > ${DBLISTFILE}

DBLIST=""
for DB in `cat ${DBLISTFILE}` ; do DBLIST="${DBLIST} ${DB}" ; done

MYSQLDUMP_OPTIONS="--routines --triggers --single-transaction"
mysqldump ${MYSQL_CONN} ${MYSQLDUMP_OPTIONS} --databases ${DBLIST} > all-dbs.sql

Tipp für Anfänger: Das Script braucht Ausführungsrechte. Also so verwenden. Mit einem Texteditor das Script erzeugen, rechte setzen und dann starten:

# Script erzeugen, ich verwende nano
nano dump.sh

# Rechte setzen
chmod +x dump.sh

# Script ausführen
./dump.sh

Das Script erzeugt die all-dbs.sql Datei, die man nun einspielen kann. Zur not auch mit -f Option.

# Auf dem neuen Server
mysql -p -f < all-dbs.sql

MySQL Benutzer und Rechte übertragen

Auch dafür habe ich im Internet ein Script gefunden, dass ich mit euch hier teilen möchte. Hier ist meine korrigierte Version davon.

Schritt 1: User-Rechte Exportieren:

Bitte daran denken, dass root Passwort zu ändern!

mysql -u root -p'PASSWORD' --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql -u root -p'PASSWORD' --skip-column-names -A | sed 's/$/;/g' > user_grants.sql

Das Script erzeugt die Datei user_grants.sql. Achtung, bitte diese Datei bearbeiten. Ich hatte Datenbanken mit Unterstrich und Bindestrich. Das Script hat es mit \ oder \\ escaped. Es ist nicht richtig, deshalb bitte die Datenbanknamen per Hand im Editor anpassen, sollten die fehlerhaft sein.

Schritt 2: User exportieren

mysql -u root -p'password' --skip-column-names -A mysql -e "SELECT CONCAT('CREATE USER \'', user, '\'@\'', host, '\' IDENTIFIED WITH \'mysql_native_password\' AS \'', authentication_string,'\';') FROM mysql.user WHERE user NOT IN ('mysql.session','mysql.sys','debian-sys-maint','root');" > create_user.sql

Schritt 3: Die User und Rechte importieren und die Rechte Flushen.

An der Shell importiert man die Dumps:

mysql -u root -p mysql < create_user.sql
mysql -u root -p mysql < user_grants.sql

Und der Privilegien-Flush wird in MySQL durchgeführt:

mysql -u root -p #root Passwort eingeben

FLUSH PRIVILEGES;
quit;

Damit lief bei mir dann alles wieder. Ich hoffe, ich habe dir mit meiner Anleitung helfen können. Wenn etwas sein sollte, schreibe es mir in die Kommentare. Wenn ich kann, versuche ich dir zu helfen.

Check Also

USV Anlage – 5 Kriterien zur richtigen Auswahl

Die Abkürzung USV steht für Unterbrechungsfreie Stromversorgung. Ist doch ganz einfach, oder? – Leider nicht. …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert