Skip to main content

MySQL

1. Benutzerverwaltung

1.1 Benutzer anzeigen

sql
-- einfache Übersicht
SELECT User, Host
FROM mysql.user;

-- inkl. Authentifizierungsinformationen (nicht direkt bearbeiten!)
SELECT User, Host, plugin, authentication_string
FROM mysql.user;

Hinweis: Die Tabelle mysql.user sollte nur gelesen werden.
Benutzer immer mit CREATE USER, ALTER USER und GRANT verwalten.

1.2 Benutzer anlegen und Berechtigungen vergeben

Anmeldung als Administrator:

bash
mysql -u root -p

Datenbank anlegen:

sql
CREATE DATABASE DBNAME
  DEFAULT CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

Benutzer nur lokal (localhost):

sql
CREATE USER 'DB_USER'@'localhost'
  IDENTIFIED BY 'DB_PASS';

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER
ON DBNAME.* TO 'DB_USER'@'localhost';

Benutzer mit Zugriff von überall (nicht empfohlen):

sql
CREATE USER 'DB_USER'@'%'
  IDENTIFIED BY 'DB_PASS';

GRANT ALL PRIVILEGES
ON DBNAME.* TO 'DB_USER'@'%';

Wichtig: Seit MySQL 8 wird ein Benutzer nicht mehr implizit über
GRANT ... IDENTIFIED BY angelegt: zuerst CREATE USER, dann GRANT.

1.3 Benutzeranmeldung

Lokal:

bash
mysql -u DB_USER -p DBNAME

Anmeldung an einem entfernten Host:

bash
mysql -u superadmin -p -h intranet-prod-mysql.irgendwas.com confluencedbtemp

1.4 Benutzer löschen

sql
DROP USER IF EXISTS 'DB_USER'@'localhost';
DROP USER IF EXISTS 'DB_USER'@'%';

2. Datenbanken und Schemata

2.1 Datenbank erstellen

sql
CREATE DATABASE ecg_otrs_intern_test
  DEFAULT CHARACTER SET utf8mb4
  COLLATE utf8mb4_unicode_ci;

2.2 Datenbank löschen

sql
DROP DATABASE db_name;

2.3 Schemagröße anzeigen

sql
SELECT table_schema,
       ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS total_mb
FROM   information_schema.tables
GROUP  BY table_schema
ORDER  BY total_mb DESC;

3. Remote-Zugriff

3.1 Server für Remote-Zugriff konfigurieren

Standardmäßig lauscht MySQL/MariaDB nur auf 127.0.0.1.

Typische Konfigurationsdateien:

  • MySQL: /etc/mysql/mysql.conf.d/mysqld.cnf
  • MariaDB: /etc/mysql/mariadb.conf.d/50-server.cnf

Beispiel:

ini
[mysqld]
# bind-address = 127.0.0.1      # Standard

# Variante 1: nur interne Adresse
bind-address = 10.0.0.5

# Variante 2: alle Interfaces (nur mit Firewall/VPN!)
# bind-address = 0.0.0.0

Dienst neu starten:

bash
systemctl restart mysql

Warnung: bind-address = 0.0.0.0 ohne Firewall oder VPN ist ein deutliches Sicherheitsrisiko.

3.2 Benutzer für Remote-Zugriff freischalten

Bereits vorhandene Benutzer mit Remote-Hosts anzeigen:

sql
SELECT User, Host
FROM mysql.user
WHERE Host <> 'localhost';

Beispiele:

sql
-- Benutzer mit Vollzugriff von einem bestimmten Host
CREATE USER 'echomike'@'ecgwin64.vngag.de'
  IDENTIFIED BY 'neuesPasswort';

GRANT ALL PRIVILEGES ON *.* TO 'echomike'@'ecgwin64.vngag.de'
  WITH GRANT OPTION;

-- Benutzer mit Zugriff aus einem Subnetz
CREATE USER 'user_otrs'@'10.96.%.%'
  IDENTIFIED BY 'otrs4test';

GRANT ALL PRIVILEGES ON ecg_otrs_intern_test.* TO 'user_otrs'@'10.96.%.%'
  WITH GRANT OPTION;

Hinweis: GRANT ALL ON *.* WITH GRANT OPTION nur sehr sparsam und nur für Admin-Konten verwenden.


4. Backup & Restore mit mysqldump

4.1 Gesamten Server sichern

bash
mysqldump -u root -p --single-transaction --all-databases > dump.sql

4.2 Einzelne Datenbank(en) sichern

bash
# eine Datenbank
mysqldump -u root -p --single-transaction DBNAME > DBNAME.sql

# mehrere Datenbanken
mysqldump -u root -p --single-transaction --databases db1 db2 > multi.sql

Beispiel mit Datumsstempel:

bash
mysqldump -u otrs -p otrs \
  > /tmp/otrs-$(date +%Y%m%d-%H%M).sql

Hinweis: --single-transaction ist für InnoDB der Standardweg, um konsistente Dumps zu erzeugen, während Anwendungen weiter schreiben können.

4.3 Restore eines Dumps (klassisch, ohne Docker)

bash
mysql -u BENUTZER -p DATENBANK < datenbank.sql

Beispiel:

bash
mysql -u root -p dfsgwhh < dump.sql -v

Hinweis: -v (--verbose) zeigt den Fortschritt ausführlicher an.

Warnung: Bei Dumps mit --all-databases wird auch die Systemdatenbank mysql mit Benutzerkonten und Rechten überschrieben.

4.4 Dump mit Fortschrittsanzeige

bash
apt install pv

pv dump.sql.gz | zcat | mysql -u user -p database

4.5 Dump per Cron (Beispiel mit Docker-Container)

bash
crontab -e
cron
# Zabbix database backup
2 0 * * * /srv/zabbix/cron/mysqldump.sh >/dev/null 2>&1

/srv/zabbix/cron/mysqldump.sh:

bash
#!/bin/bash

USER=zabbix
PASSWORD=PASSWORD
OUTPUT="/srv/exx/tmp_dbdumps/"
CONTAINER=zabbix-db
DATABASE=zabbix
DATE=$(date +%Y-%m-%d)
[email protected]
HOSTNAME=$(cat /proc/sys/kernel/hostname)

# Backup-Verzeichnis anlegen
if [ ! -d "$OUTPUT" ]; then
   mkdir -p "$OUTPUT"
fi

rm -f "$OUTPUT"/zabbix*

# Dump aus Docker-Container
docker exec "$CONTAINER" \
  mysqldump -u "$USER" --password="$PASSWORD" \
  --single-transaction "$DATABASE" \
  > "$OUTPUT/${DATABASE}_${DATE}.sql"

if [ "$?" -eq 0 ]; then
   rm -f /srv/exx/z_backups/*.*
   cp "$OUTPUT"/zabbix* /srv/exx/z_backups/
   echo "DB Backup erfolgreich"
else
   echo "$HOSTNAME - DB Backup $DATABASE - $DATE fehlgeschlagen" | \
   mail -s "$HOSTNAME - DB Backup $DATABASE - $DATE fehlgeschlagen" -- "$MAILTO"
fi

4.6 Restore, wenn MySQL/MariaDB im Docker-Container läuft

Bei MySQL/MariaDB im Docker-Container wird der Restore über docker exec ausgeführt.
Das < dump.sql passiert auf dem Host, nicht im Container.

4.6.1 Einzelne Datenbank in einem Container zurückspielen

Beispiel:

bash
docker exec -i zabbix-db \
  mysql -u zabbix --password=PASSWORD zabbix \
  < /srv/exx/z_backups/zabbix_2025-01-01.sql

Hinweis:

  • -i streamt den Dump über stdin in den Container
  • zabbix-db ist der Containername
  • mysql -u zabbix ... zabbix verbindet sich auf die Datenbank zabbix

Der Dump wurde typischerweise mit:

bash
mysqldump -u zabbix -p --single-transaction zabbix > zabbix_2025-01-01.sql

erstellt und enthält keinen CREATE DATABASE.

4.6.2 Kompletten Server-Dump (--all-databases) zurückspielen

bash
docker exec -i mysql-db \
  mysql -u root --password=ROOTPASS \
  < /pfad/zu/dump-all.sql

Hinweis:

  • Dump enthält alle Datenbanken inkl. mysql (Benutzer und Rechte)
  • Für vollständige Neuinstallation geeignet, sonst kritisch

4.6.3 Datenbank vor dem Restore neu anlegen/aufräumen

bash
# Datenbank im Container neu anlegen
docker exec mysql-db \
  mysql -u root --password=ROOTPASS \
  -e "DROP DATABASE IF EXISTS confluencedb;
      CREATE DATABASE confluencedb
        CHARACTER SET utf8mb4
        COLLATE utf8mb4_unicode_ci;"

# Dump in die frisch angelegte DB einspielen
docker exec -i mysql-db \
  mysql -u root --password=ROOTPASS confluencedb \
  < /pfad/zu/confluencedb.sql

4.6.4 Restore aus einem separaten Client-Container

Alternative über einen eigenen MySQL-Client-Container im selben Docker-Netzwerk:

bash
docker run --rm -i --network=my-net \
  -v /srv/backups:/backups \
  mysql:8 \
  mysql -h mysql-db -u root --password=ROOTPASS confluencedb \
  < /srv/backups/confluencedb.sql

Hinweis:

  • --network=my-net: gemeinsames Docker-Netzwerk
  • /srv/backups: Host-Verzeichnis mit Dumps

4.6.5 Typische Fehlerquellen

  • "Access denied for user …"
    → Benutzer/Passwort/Host (User@Host) prüfen
  • "Unknown database …"
    → Datenbank anlegen oder prüfen, ob der Dump CREATE DATABASE enthält
  • Container nicht erreichbar
    docker ps, Docker-Netzwerk, Ports und Firewall prüfen

4.6.6 Alte MySQL-Daten im Docker-Setup aufräumen

Wenn eine MySQL-/MariaDB-Instanz im Docker-Setup komplett verworfen und "frisch" neu aufgebaut werden soll, kann das gemountete Datenverzeichnis auf dem Host gelöscht werden.

Achtung:

  • Danach sind alle Daten und Benutzer endgültig gelöscht
  • Nur machen, wenn ein verlässlicher Dump existiert
  • Pfad und Volume-Mapping genau kontrollieren

Beispiel (Volume auf ./data/mysql):

bash
# Container stoppen
docker compose stop joomla_db

# Datenverzeichnis entfernen (zerstörerisch!)
rm -rf ./data/mysql

# Container mit leerem Datenverzeichnis neu starten
docker compose up -d joomla_db

Beim nächsten Start initialisiert MySQL/MariaDB die Systemtabellen neu.
Anschließend kann ein Dump wie oben beschrieben eingespielt werden.


5. Binary Logging

5.1 Konfiguration (MySQL < 8.4 / MariaDB)

ini
[mysqld]
log_bin          = /var/log/mysql/mysql-bin.log
expire_logs_days = 2
max_binlog_size  = 50M

5.2 MySQL 8.4 und neuer

expire_logs_days ist entfernt, stattdessen:

ini
[mysqld]
log_bin                    = /var/log/mysql/mysql-bin.log
binlog_expire_logs_seconds = 172800  # 2 Tage
max_binlog_size            = 50M

Zum Deaktivieren des Binary Logging log_bin auskommentieren/entfernen
(nur tun, wenn keine Replikation / Point-in-Time-Recovery benötigt wird).


6. Konfiguration (my.cnf / .my.cnf)

6.1 MySQL/MariaDB-Konfigurationsdateien

Typische Orte:

  • /etc/mysql/my.cnf (Hauptdatei mit Includes)
  • /etc/mysql/mysql.conf.d/mysqld.cnf (MySQL-Server)
  • /etc/mysql/mariadb.conf.d/50-server.cnf (MariaDB-Server)

6.2 Persönliche Client-Konfiguration (~/.my.cnf)

Erlaubt Login ohne Passwort auf der Kommandozeile:

ini
[client]
host     = localhost
user     = root
password = 123456

[mysqldump]
user     = root
password = 123456

Sicherheit:

  • Datei auf den jeweiligen Benutzer beschränken: chmod 600 ~/.my.cnf
  • Für produktive Umgebungen besser dedizierte Backup-User mit eingeschränkten Rechten nutzen

6.3 Root-Passwort ändern

Moderne Variante (MySQL 5.7+/8.x, MariaDB):

sql
ALTER USER 'root'@'localhost'
  IDENTIFIED BY 'NeuesSicheresPasswort';

Ältere Variante mit mysqladmin:

bash
mysqladmin -u root -p password

Bei Distributionen mit auth_socket-Plugin kann zuvor ein Wechsel des Plugins nötig sein.

6.4 mysql_upgrade (nur Altversionen)

Ältere MySQL-Versionen:

bash
mysql_upgrade -u root -p -h localhost

Hinweis:

  • Bis MySQL 8.0.15 relevant
  • Seit 8.0.16 wird das Schema beim Serverstart automatisch aktualisiert
  • In neueren Versionen ist mysql_upgrade entfernt

7. Monitoring mit mytop

mytop zeigt laufende Queries ähnlich wie top.

Installation (Debian/Ubuntu):

bash
apt install mytop

Verwendung:

bash
mytop -d mysql

8. Nützliche SQL-Befehle (Beispiel Mailserver)

8.1 Datenbank auswählen

sql
USE mailbase;

8.2 Tabellen anzeigen

sql
SHOW TABLES;
```

Beispielausgabe:
```
+--------------------+
| Tables_in_mailbase |
+--------------------+
| domains            |
| mailusers          |
| weiterleitungen    |
+--------------------+

8.3 Tabelleninhalte anzeigen

sql
SELECT * FROM domains;
```

Beispiel:
```
+----+-----------------------------+
| id | domain                      |
+----+-----------------------------+
|  1 | irgendwas.de                |
|  2 | nochwas.de                  |
+----+-----------------------------+

8.4 Datensätze einfügen

sql
INSERT INTO mailusers
SET account       = '[email protected]',
    maildir       = 'irgendwas.de/p.meier',
    home          = '/var/spool/maildirs',
    password      = 'DevCiphEqu',
    angelegt_von  = 'm.müller',
    angelegt_am   = CURDATE();

INSERT INTO weiterleitungen
SET forward_from  = '[email protected]',
    forward_to    = '[email protected]',
    angelegt_von  = 'm.müller',
    angelegt_am   = CURDATE();

Hinweis: In realen Mail-Setups werden Passwörter in der Regel gehasht gespeichert.

8.5 Suchen

sql
-- exakte Suche
SELECT * FROM weiterleitungen
WHERE forward_from = '[email protected]';

-- unscharfe Suche mit LIKE
SELECT * FROM weiterleitungen
WHERE forward_from LIKE '%pressestelle%';
```

Beispielausgabe:
```
+-----+-------------------------------+----------------------------+--------------+-------------+----------+
| id  | forward_from                  | forward_to                 | angelegt_von | angelegt_am | memo_txt |
+-----+-------------------------------+----------------------------+--------------+-------------+----------+
| 751 | [email protected]     | [email protected]       | m.müller     | 2015-09-08  |          |
+-----+-------------------------------+----------------------------+--------------+-------------+----------+

8.6 Löschen

sql
DELETE FROM weiterleitungen
WHERE id = 751;

8.7 Werte ändern

sql
UPDATE weiterleitungen
SET angelegt_von = 'k.lehmann'
WHERE forward_from = '[email protected]';

9. Hinweise zu Locks während mysqldump

Früher:

  • "Während des Dumps kann nicht in die Tabellen geschrieben werden."

Genauer:

  • Ohne --single-transaction und bei MyISAM-Tabellen werden Tabellen gesperrt (Schreibzugriffe blockiert)
  • Mit --single-transaction und InnoDB können Anwendungen weiter schreiben, während mysqldump einen konsistenten Snapshot liest

Für moderne Installationen mit InnoDB ist:

bash
mysqldump --single-transaction ...

die Standardempfehlung.