datenbanken:mysql

Dies ist eine alte Version des Dokuments!


MySQL

MySQL [ˌmaɪɛskjuːˈɛl] ist ein Relationales Datenbankverwaltungssystem der schwedischen Firma MySQL AB die mittlerweile 1) durch Sun Microsystems übernommen wurde. MySQL ist als Open-Source-Software für verschiedene Betriebssysteme verfügbar.

MySQL.odp MySQL.pdf

Befehl / Programm Funktion
mysqld MySQL server daemon (=Dienst)
safe_mysqld Server prozess Monitor
mysqlaccess Programm zum Erzeugen von MySQL-Benutzern
mysqladmin Administrationstool
mysqldump Programm für das Erstellen von Datenbankbackups („dump“)
mysql Kommandozeilenzugriff auf MySQL
mysqlshow listest alle MySQL-Datenbanken auf

kompilieren aus den Quellen:

(entpacken: tar xvzf ARCHIVDATEI)
./configure
make
make install

mindestens für den letzten Schritt braucht man root-Rechte (also mit sudo oder als root starten) und für alle folgenden Möglichkeiten auch.

als vorkompiliertes Paket installieren:

  • rpm-Paket (Suse, Redhat, Fedora, …): rpm -i PAKETDATEI.rpm oder
  • deb-Paket (Debian, (K)ubuntu): dpkg -i PAKETDATEI.deb

Oder am einfachsten aus einem Repository (Sammlung von Paketen, meist direkt aus dem Internet):

  • yum (Suse, Redhat, Fedora, …): yum install mysql
  • apt (Debian, K)ubuntu): ap-get install mysql
apt purge  -y mysql-server mysql-server-5.7 mysql-server-core-5.7
apt purge  -y mysql-client-5.7 mysql-client-core-5.7 mysql-common
rm -Rf /etc/mysql
rm -Rf /var/lib/mysql
# prüfen ob /etc/apparmor.d/usr.sbin.mysqld sauber ist oder "aa-remove-unknown" ausführen
service apparmor teardown
service apparmor start

Aktuelle Konfiguration des laufenden Servers:

mysqladmin variables -p

Konfiguration testen: mysqld –validate-config

Einige Einstellungen von MySQL: Datei /etc/mysql/my.conf

bindaddress = 127.0.0.1

WICHTIG: soll nur auf lokale Anfragen antworten, sonst lauscht mysql auf Logins von anderen Hosts (das sollte man nur erlauben wenn es benötigt wird, z.B. bei spezialisierten Datenbankservern)

user = mysql

Der Benutzer unter dem mysql läuft, am besten auch überprüfen das sich der Nutzer mysql nicht über ssh einloggen kann.

port = 3306

Der Port auf dem Mysql auf Anfragen lauscht.

# log = /var/log/mysql.log
# log = /var/log/mysql/mysql.log

Extra-logdateien für Mysql, standardmäßig auskommentiert weil die Dateien (abhängig von der Menge der Anfragen) schnell groß werden und Leistung kosten.

Beim dist-upgrade von ubuntu 18.04 zu 20.04 (Version 5.7 auf 8.0) werden folgenden Einstellungen werden nicht mehr unterstützt:

query_cache_type
query_cache_size
query_cache_limit
innodb_large_prefix
innodb_file_format
show_compatibility_56
  • Symptom: mysqld & systemd - errno: 24 - Too many open files; soft limit ist standardmäßig 1024, hard limit 4096.
  • check mit:
    cat /proc/$(cat /var/run/mysqld/mysqld.pid)/limits | grep files

Ein Eintrag in der /etc/security/limits.conf hilft nichts

mysql soft nofile 65535
mysql hard nofile 65535
  1. Methode 1 (override):
    systemctl edit mysql

    (legt an: /etc/systemd/system/mysql.service.d/override.conf)

    [Service]
    LimitNOFILE=infinity
    LimitMEMLOCK=infinity
  2. Methode 2: unit-file direkt editieren: /etc/systemd/system/multi-user.target.wants/mysql.service
    LimitNOFILE=infinity
    LimitMEMLOCK=infinity
    systemctl daemon-reload
Parameter Bedeutung Default
query_cache_limit Gibt den Maximalwert eines gecachten Objekts an. Der Standardwert ist in der Regel 2 MB. Bei Abfragen mit großen Ergebnissen kann es Sinn machen, diesen Wert leicht zu erhöhen.
query_cache_size Gibt die Maximalgröße des Query Caches an. Sollte bei stark belastetetn Systemen ruhig auf 32 oder 64 MB gesetzt werden.
table_cache Anzahl der gecachten Tables. Diese Einstellungen muss eigentlich fast immer erhöht werden.
tmp_table_size Größe der maximal implizit im RAM erzeugten temporären Tabellen. Diese Einstellung muss ebenfalls fast immer vergrößert werden. Beispielsweise auf 64 MB Nein, MySQL: 16M
Parameter Bedeutung Default
innodb_flush_method auf O_DIRECT setzen!
innodb_buffer_pool_size Gibt die Größe des Speichers an, in dem die InnoDBs verwaltet werden. Hier gilt: Viel hilft viel. In einer idealen Welt sollte der Wert so groß sein, dass die gesamte DB hier Platz findet.
innodb_file_per_table Unbedingt setzen! Dadurch wird pro Table eine Datei angelegt. Das lässt sich wesentlich besser verwalten als eine riesige Datei. Ja: MySQL mariaDB
innodb_data_file_path Gibt an wie die Datenbankdateien heißen und wie sie vergrößert werden. Bitte auf folgendes setzen: innodb_data_file_path=ibdata1:10M:autoextend 5.6(12M) 5.7 mariaDB
MyIsam
key_buffer Gibt den Buffer für MyIsam Tabellen an. Es ist quasi die innodb_buffer_pool_size für MyIsam*.* Auch hier gilt: Viel hilft viel. Es reicht allerdings, wenn sämtliche Indexe in den Buffer passen.

mysqladmin (Befehle z.B. status, create, drop, stop)

Benutzer (db mysql,tabelle user)
Rechte (globale [admins], lokale [user]: auf eine Datenbank beschränkte Rechte)

Offline-Backup

Wenn man den Server nicht rund um die Uhr verfügbar haben muss, kann man ein Offline-Backup machen. Dazu
  1. stoppt man den Server
    /etc/init.d/mysqld stop
  2. kopiert alle Datendateien (mit cp, rsync oder einer anderen Möglichkeit) unter /var/lib/mysql z.B. nach /tmp/mysql-backup:
    cp -r /var/lib/mysql /tmp/mysql-backup
  3. und startet den Server wieder
    /etc/init.d/mysqld start

Online-Backups (während des Betriebs) haben jedoch den Vorteil nicht nur die Binärdateien zu sichern (die Versions-/Architekturabhängig sind!) sondern korrekte SQL-Statements zu produzieren die wieder eingespielt werden können.

mysqldump -B db1 db2 db3 -u root -p Passwort > Backupdatei.sql
Option Effekt
--all-databases sichert alle Datenbanken
-B Datenbanken (hier db1 db2 db3), die man sichern will
-u user für mysql
-p Passwort, wenn keins angegeben ist fragt er nach. Alternativ kann das Passwort auch in der Datei .my.conf im home-Verzeichnis gesichert werden: :!: siehe MySQL-Doku - Password-Security.
Der Speicherort des „Option-File“ kann auch per Option angegeben werden: --defaults-file=/etc/my.cnf. Bei Debian sind die Zugangsdaten fürfür die Paketverwaltung in /etc/mysql/debian.cnf abgelegt.

Das ganze wird dann in Backupdatei.sql geschrieben und kann später wieder zurückgespielt werden.

Offline-Backup

Für regelmäßige Backup müsste man die Zugangsdaten auf dem System hinterlegen. Das wäre mit einem Administrativen Zugang eher problematisch. Es geht aber auch anders: Es reicht einen beschränkten Benutzer anzulegen der lediglich die notwendigsten Rechte erhält:
  1. „SELECT“
  2. „FILE“
  3. PROCESS (wenn Tablespaces dedumpt werden sollen 2) )
  4. und „LOCK TABLES“ (in den Kästen „Daten“ und „Administration“ wenn man das per phpmyadmin durchführt)
    CREATE USER 'dump'@'localhost' IDENTIFIED BY 'GEHEIM';
    GRANT SELECT, FILE, PROCESS, LOCK TABLES ON *.* TO 'dump'@'localhost';

Weniger sicher ist ein direkter insert in die Tabelle user:

mysql> USE mysql;
mysql> INSERT INTO user SET Host ='localhost', User = 'dump', Password = Password('GEHEIM'), Select_priv ='Y', File_priv ='Y', Lock_tables_priv ='Y';
mysql> FLUSH PRIVILEGES;

Ab Version 5.7 heißt das Feld statt „Password“ nun „authentication_string“ und das Feld ssl_cipher braucht einen Wert:

ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value

In der Konsole sollte folgender Befehl erfolgreich sein:

mysqldump -u dump -pGEHEIM --all-databases > Backup.sql

Oder das Passwort liegt in einer Datei /root/.my.cnf:

mysqldump --defaults-file=/root/.my.cnf -u dump --all-databases > backup.sql

wobei /root/.my.cnf den folgenden Inhalt hat:

[client]
password=GEHEIM

Zmanda

  1. Db erzeugen:
    mysqladmin -u root -p create dbname
  2. SQL-Datei einspielen
    mysql [opt] dbname < datei.sql -u root

Falls der SQL-Dump schon eine Datenbank anlegt:

mysql --user=user_name --password=geheim < datei.sql

Ein kleiner Funktionstest im laufenden Betrieb:

/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf ping
mysqld is alive

MySQL Performance Analyzer von Yahoo

MySQL-Benutzer anlegen

Der SQL-Code:

CREATE USER 'DBUSER1'@'%' IDENTIFIED WITH mysql_native_password;
GRANT USAGE ON *.* TO 'DBUSER1'@'%' REQUIRE NONE WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;SET PASSWORD FOR 'DBUSER1'@'%' = '***';
CREATE DATABASE IF NOT EXISTS `DBUSER1`;
GRANT ALL PRIVILEGES ON `DBUSER1`.* TO 'DBUSER1'@'%';
#!/bin/sh
 
# DB erzeugen
user=DBUSER1 # ÄNDERN!
db="$user"  # kann, muss aber nicht gleich sein.
hostname="localhost"
db_pass_file=$(mktemp)
sql_file=$(mktemp)
pwgen 18 > "$db_pass_file" # pwgen muss installiert sein
# könnte auch mit urandom ersetzt werden:
# db_pass_file=$(tr -cd -- "-._\!+a-zA-Z0-9" < /dev/urandom | head -c 18 && echo)
 
echo "CREATE USER '$user'@'$hostname' IDENTIFIED BY '$(cat "$db_pass_file")';" >> "$sql_file"
echo "GRANT USAGE ON *.* TO '$user'@'$hostname' IDENTIFIED BY '$(cat "$db_pass_file")' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;" >> "$sql_file"
echo "CREATE DATABASE IF NOT EXISTS \`$db\`;" >> "$sql_file"
echo "GRANT ALL PRIVILEGES ON \`$db\`.* TO '$user'@'$hostname';" >> "$sql_file"
 
echo "Enter mysql-password: "
mysql -u root -p < "$sql_file"

Alte Methode:

SQL-Befehle zum anlegen eines neuen Benutzers user1 mit dem passwort „passwort1“, der alle Benutzerrechte für die neue Datenbank db1 bekommt.

CREATE USER 'user1'@'localhost' IDENTIFIED BY 'passwort1';
GRANT USAGE ON *.* TO 'user1'@'localhost' IDENTIFIED BY 'passwort1' WITH MAX_QUERIES_PER_HOUR 0 MAX_CONNECTIONS_PER_HOUR 0 MAX_UPDATES_PER_HOUR 0 MAX_USER_CONNECTIONS 0;

CREATE DATABASE IF NOT EXISTS `db1` ;

GRANT ALL PRIVILEGES ON `db1`.* TO 'user1'@'localhost';

Benutzer löschen

DROP USER 'BENUTZERNAME'@'%';
FLUSH PRIVILEGES;

Benutzer anzeigen

SELECT USER,password,plugin,host FROM mysql.user;

ab 5.7.x:

SELECT USER,authentication_string,plugin,host FROM mysql.user;

Passwort Ändern

use mysql;
update user set password=PASSWORD("GEHEIM") where User='BENUTZERNAME';

ab Version 5.7.x:

use mysql;
update user set authentication_string=PASSWORD("GEHEIM") where User='BENUTZERNAME';
flush privileges;
quit

Rechte eines Benutzers

SHOW GRANTS; SHOW GRANTS FOR CURRENT_USER();

Plugin "localhost"

Durch das Plugin „localhost“ kann sich root von localhost aus ohne Authentifizierung anmelden. Dieses Verhalten ist möglicherweise unerwünscht.

Abschalten

UPDATE mysql.user SET plugin = '' WHERE USER = 'root' AND host = 'localhost';

https://stackoverflow.com/questions/44298160/mysql-mariadb-10-0-29-set-root-password-but-still-can-login-without-asking-p

Replication ist das duplizieren der Daten auf einen anderen Server. Damit wird sichergestellt, dass die Daten konsistent bleiben, da beim einfachen Dump im laufenden Betrieb Inkonsistenzen durch nicht vollständige Transaktionen auftreten können.

Im Grunde genommen sehr grundsätzliche Dinge

  • MySQL nicht als root betreiben (diese Sünde begeht hoffentlich keiner)
  • Systemsicherung
  • Benutzerrechte sinnvoll vergeben (USAGE-Rechte für jede Applikation)
  • Aufteilung in Datenbanken mit eigenen Rechte wo möglich
  • entfernten (Netzwerk-) Zugriff beschränken/abschalten

Wie sichere ich MySQL gegen Hacker ab ? Keeping Your Password Secure Securityfocus: Securing MySQL Securing MySQ Securing a MySQL Server on Windows

MySQL Lockdown Checklist

Source

FIXME Eng → D

The following is a quick-reference list of things to do when you're tightening the security of your MySQL server. Other excellent lists can be found at

http://www.databasesecurity.com/mysql.htm http://www.securityfocus.com/infocus/1667 http://www.kitebird.com/articles/ins-sec.html

  • Read the MySQL security guidelines at http://dev.mysql.com/doc/mysql/en/Security.html
  • Deploy either IPTables (Linux) or an IPSec filtering ruleset (Windows) on your MySQL servers.
  • Visit http://www.mysql.com/products/mysql/ often, and check for updates.
  • Remove all non-root MySQL users
  • Rename the 'root' MySQL user to something obscure
  • Create a MySQL user for each web application – or possibly for each 'role' within each web application. For instance, you might have one MySQL user that you use to update tables, and another, lower-privileged user that you use to 'select' from tables. Ensure that MySQL users are restricted by IP address as well as passwords. See section 5.4 of the MySQL manual, “The MySQL Access Privilege System” for more information.
  • Use a low – privileged 'mysql' account to run the MySQL daemon. This is the default on some platforms, but not others. For example, MySQL runs as the local 'system' account under Windows.
  • Run mysqld with the '--chroot' option. Ensure that the MySQL user cannot access files
  • outside of a limited set of directories. Specifically, the MySQL user should be prohibited from reading operating system configuration files. In some cases you might want to prevent the MySQL user from being able to modify the MySQL configuration files.
  • Don't give accounts privileges that they don't absolutely need, especially 'File_priv' and 'Grant_priv'. If you have to interact with the file system from within MySQL, consider creating a seperate MySQL account that your application can use for this purpose.
  • Disable the LOAD DATA LOCAL INFILE command by adding “set-variable=local-infile=0” to the my.cnf file.
  • Know your bugs! Check vulnerability databases such as SecurityFocus and ICAT regularly for MySQL bugs.

Wenn der Start von MySQL nicht klappt, sollte man sich erstmal in den Log-Dateien schlau machen. Er guter Anlaufpunkt ist dabei das Systemlog (/var/log/syslog) in der sich dann evtl. folgende (von mir gekürzte!) Zeile finden lässt:

mysqld_safe[14698]: started
mysqld[14701]: InnoDB: Started; log sequence number 0 43655
mysqld[14701]: [ERROR] Can't start server: Bind on TCP/IP port: Cannot assign requested address
mysqld[14701]: [ERROR] Do you already have another mysqld server running on port: 3306 ?
mysqld[14701]: [ERROR] Aborting

MySQL kann sicht also nicht an den Port 3306 binden. Jetzt gibt es zwei einfache Problemursachen:

  1. ein anderes Programm (oder eine andere MySQL-Instanz?) hat sich bereits den Port 3306 geschnappt. Das sollte man mit (sudo netstat -tulpen) nachprüfen. In diesem Fall existiert eine ähnliche Zeile zu
    Aktive Internetverbindungen (Nur Server)
    Proto Recv-Q Send-Q Local Address           Foreign Address         State       Benutzer   Inode      PID/Program name   
    tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN     109        26526      22498/mysqld 
  2. man hat MySQL eine fehlerhafte IP angegeben, die dann die Bindung an Port 3306 scheitern lässt. Dazu sollte man einmal in /etc/mysql/my.cnf nach der Zeile
    bind-address = 127.0.0.1

    schauen. Mit einem Befehl:

    grep bind-address /etc/mysql/my.cnf

Als IP ist natürlich auch eine andere möglich, etwa wenn die Datenbank über Netzwerk erreichbar sein soll. Wenn diese IP nicht dem aktuellen Stand entspricht (etwa weil diese IP über DHCP vergeben worden ist und man nun eine neue hat) scheitert die Bindung zwangsläufig. Im Zweifel kann man mit sich mit ifconfig die aktuellen IPs der Netzwerkschnittstellen anzeigen lassen und einmal mit ping IP (wobei IP durch die eingetragene IP ersetzt werden muss) einen Kontaktversuch unternehmen kann. So ist es mir auch schon einmal untergekommen, das die Netzwerkschnittstelle loopback (lo) durch eine Fehleinrichtung nicht die IP 127.0.0.1 hatte.

:!: Can't connect to [local] MySQL server

Reparatur anstoßen:

repair table TABELLENNAME;

Quelle: mysql table is marked as crashed and last (automatic?) repair failed

Die Binary Logs sind zur Absicherung von Schreibzugriffen in Replikationens-Umgebungen und Restore gedacht.

Logs sofort „purgen“:

mysql> PURGE BINARY LOGS BEFORE (date(now()) + interval 0 second - interval 2 day);

Für die Sitzung:

mysql> set global expire_logs_days = 2;

Dauerhaft: /etc/mysql/my.cnf

[mysqld]
expire_logs_days=2

MySQL bietet verschiedene Speicher-Engines für den Zugriff auf die Daten an. Jedes ist auf ihr Einsatz-Szenario optimiert.

MyISAM ist die Standard-Speicher-Engine von MySQL unter UNIX-basierten Systemen und ist für schnellen Zugriff auf Tabellen und Indizes ohne Transaktionssicherung gedacht.

Transaktionen bietet InnoDB an und ist unter Windows als die default-Engine eingestellt, allerdings unterstützt InnoDB keine Volltextsuche.

Wikipedia bietet einen guten Überblick über alle Speicher-Engines von MySQL.

Ein Datenbankindex, oder kurz Index, ist eine von den Datenstruktur getrennte Indexstruktur in einer Datenbank, die die Suche und das Sortieren nach bestimmten Feldern beschleunigt.

Ein Datenbanktrigger, meist nur Trigger genannt, ist eine Funktionalität von diversen Datenbankmanagementsystemen, insbesondere von großen relationalen Datenbankmanagementsystemen.

Der Begriff Gespeicherte Prozedur (GP) oder englisch Stored Procedure (SP) bezeichnet eine Funktion bestimmter Datenbankmanagementsysteme. In einer Stored Procedure können ganze Abläufe von Anweisungen unter einem Namen gespeichert werden, die dann auf dem Datenbankserver zur Verfügung stehen und ausgeführt werden können. Mit anderen Worten: Eine SP ist ein eigenständiger Befehl, der eine Abfolge von gespeicherten Befehlen ausführt.

Benutzerdefinierte Funktionen (engl. User Defined Function, Abk. UDF)) werden in Datenbanksystemen verwendet.


1)
seit Februar 2008
2)
mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces