oxmysql einrichten: Connection-String, server.cfg und sichere Queries für FiveM

oxmysql•Von Web-Services Team••9 Min. Lesezeit

Um oxmysql einzurichten, legst du die Resource in deinen resources-Ordner, setzt in der server.cfg die Convar mysql_connection_string mit Benutzer, Passwort, Host und Datenbankname und startest oxmysql vor deinem Framework. In eigenen Scripts bindest du anschließend @oxmysql/lib/MySQL.lua im fxmanifest.lua ein und schreibst Queries ausschließlich mit Platzhaltern. Die meisten Probleme entstehen nicht in oxmysql selbst, sondern bei Rechten, Startreihenfolge und falsch kodierten Passwörtern.

Diese Anleitung geht die Einrichtung technisch durch, zeigt die wichtigsten API-Aufrufe, den Umstieg von mysql-async und die Fehlermeldungen, die du in der Serverkonsole am häufigsten siehst.

Was brauchst du, bevor du oxmysql einrichtest?

oxmysql ist ein Datenbank-Wrapper für FiveM, der auf dem Node-Treiber mysql2 aufsetzt. Er spricht sowohl MySQL als auch MariaDB an. Du brauchst also einen laufenden Datenbankserver, der vom FiveM-Server aus erreichbar ist, entweder lokal auf derselben Maschine oder über das Netzwerk.

Außerdem solltest du vorab klären, welche Datenbank dein Framework erwartet. ESX, QBCore und QBox bringen jeweils eigene SQL-Dateien mit, die du vor dem ersten Start importierst. oxmysql legt keine Tabellen an, es stellt nur die Verbindung und die Abfrage-Funktionen bereit.

  • MySQL- oder MariaDB-Server mit Zugriff per TCP
  • eine leere Datenbank, z. B. fivem
  • ein eigener Datenbank-Benutzer statt root
  • die aktuelle oxmysql-Release-Version, nicht den Quellcode-Branch, da der Build fehlen kann

oxmysql einrichten in fünf Schritten

  1. Datenbank und Benutzer anlegen. Verbinde dich mit deinem Datenbankserver und erstelle eine Datenbank mit utf8mb4, damit Emojis und Sonderzeichen in Charakternamen oder Nachrichten keine Fehler auslösen.
    CREATE DATABASE fivem CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    CREATE USER 'fivem'@'127.0.0.1' IDENTIFIED BY 'LangesZufallsPasswort';
    GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP ON fivem.* TO 'fivem'@'127.0.0.1';
    FLUSH PRIVILEGES;
    Der Benutzer hat nur Rechte auf diese eine Datenbank. Wird ein Script kompromittiert, bleiben andere Datenbanken auf demselben Server unangetastet.
  2. Framework-SQL importieren. Spiele die SQL-Datei deines Frameworks und die SQL-Dateien deiner Scripts in die neue Datenbank ein. Fehlende Tabellen sind später eine der häufigsten Fehlerquellen.
  3. Resource ablegen. Entpacke das Release nach resources/[standalone]/oxmysql oder in einen Ordner deiner Wahl. Wichtig ist, dass der Ordnername exakt oxmysql lautet, weil andere Resources ihn so referenzieren.
  4. Connection-String setzen. Trage die Verbindungsdaten in die server.cfg ein, idealerweise über eine separate Datei (siehe nächster Abschnitt).
  5. Startreihenfolge festlegen. oxmysql muss vor allen Resources starten, die die Datenbank nutzen.
    exec secrets.cfg
    
    ensure oxmysql
    ensure es_extended   # bzw. qb-core oder qbx_core
    ensure ox_lib
    # danach deine Scripts

Nach dem Start sollte in der Konsole eine Meldung erscheinen, dass oxmysql mit der Datenbank verbunden ist, inklusive Server-Version. Fehlt diese Zeile, brauchst du gar nicht erst im Framework nach Fehlern suchen.

Wie sieht der Connection-String richtig aus?

oxmysql akzeptiert zwei Formate. Die URI-Schreibweise ist kompakt und verbreitet:

set mysql_connection_string "mysql://fivem:LangesZufallsPasswort@127.0.0.1:3306/fivem?charset=utf8mb4"

Alternativ gibt es die Schlüssel-Wert-Schreibweise mit Semikolons:

set mysql_connection_string "user=fivem;password=LangesZufallsPasswort;host=127.0.0.1;port=3306;database=fivem;charset=utf8mb4"

Ein Detail, das viele Stunden kostet: Enthält dein Passwort Zeichen wie @, #, / oder :, bricht die URI-Schreibweise das Parsing. Entweder kodierst du diese Zeichen per URL-Encoding (@ wird zu %40) oder du nutzt die Semikolon-Variante. Am einfachsten ist ein langes Passwort nur aus Buchstaben und Ziffern.

set statt setr und eine eigene Secrets-Datei

Verwende für den Connection-String immer set, niemals setr. Mit setr repliziert der Server die Convar an die Clients, und damit landen Datenbank-Zugangsdaten bei jedem Spieler. Die wichtigste Regel beim Einrichten von oxmysql lautet: Zugangsdaten bleiben serverseitig, und jede Query nutzt Platzhalter statt zusammengesetzter Strings.

Lege die Zeile zusätzlich in eine eigene Datei secrets.cfg und lade sie per exec secrets.cfg. So kannst du die server.cfg versionieren oder mit dem Team teilen, ohne das Passwort mitzuverteilen. Die Secrets-Datei gehört in deine .gitignore.

Wie bindest du oxmysql in eigene Scripts ein?

Im fxmanifest.lua deiner Resource lädst du die Lua-Bibliothek nur serverseitig:

fx_version 'cerulean'
game 'gta5'

dependency 'oxmysql'

server_scripts {
    '@oxmysql/lib/MySQL.lua',
    'server/main.lua'
}

Danach steht dir das globale MySQL-Objekt zur Verfügung. Jede Funktion gibt es als Callback-Variante und als .await-Variante, die innerhalb eines Threads oder Events wartet, bis das Ergebnis da ist.

-- eine Zeile oder nil
local row = MySQL.single.await('SELECT firstname, lastname FROM users WHERE identifier = ?', { identifier })

-- ein einzelner Wert
local anzahl = MySQL.scalar.await('SELECT COUNT(*) FROM owned_vehicles WHERE owner = ?', { identifier })

-- Insert, liefert die neue ID
local id = MySQL.insert.await('INSERT INTO ws_logs (identifier, action) VALUES (?, ?)', { identifier, 'login' })

-- Update, liefert die Anzahl betroffener Zeilen
local changed = MySQL.update.await('UPDATE users SET job = ? WHERE identifier = ?', { 'police', identifier })

Die Rückgabewerte sind gezielt unterschiedlich. Prüfe bei update die Anzahl betroffener Zeilen, statt einfach von Erfolg auszugehen. Ist sie 0, existiert der Datensatz nicht oder die Bedingung passt nicht, und dein Script sollte darauf reagieren.

Platzhalter statt String-Verkettung

Baue niemals Werte direkt in den SQL-String ein, etwa mit '... WHERE name = ' .. name. Jeder Wert, der vom Client kommt, kann sonst SQL einschleusen. Mit ? oder benannten Platzhaltern wie @identifier übergibt oxmysql die Werte getrennt an den Treiber, der sie korrekt escaped. Wie du zusätzlich Eingaben serverseitig prüfst, bevor sie überhaupt die Datenbank erreichen, beschreibt der Beitrag zum eigenen Job-Script mit serverseitiger Validierung.

Transaktionen für zusammengehörige Änderungen

Sobald zwei Änderungen nur gemeinsam Sinn ergeben, etwa eine Überweisung zwischen zwei Konten, gehören sie in eine Transaktion. Schlägt eine Query fehl, wird alles zurückgerollt und es entsteht kein Geld aus dem Nichts.

local ok = MySQL.transaction.await({
    { query = 'UPDATE bank_accounts SET balance = balance - ? WHERE owner = ? AND balance >= ?', values = { betrag, von, betrag } },
    { query = 'UPDATE bank_accounts SET balance = balance + ? WHERE owner = ?', values = { betrag, an } }
})

if not ok then
    print(('[bank] Überweisung von %s fehlgeschlagen'):format(von))
end

Beachte die Bedingung balance >= ? in der ersten Query. Sie verhindert negative Kontostände direkt in der Datenbank, unabhängig davon, was der Lua-Code vorher geprüft hat.

Umstieg von mysql-async: was musst du anpassen?

Viele ältere ESX-Resources nutzen noch mysql-async. oxmysql deklariert sich im eigenen Manifest als Ersatz und bringt eine Kompatibilitätsschicht für die alten Aufrufe mit. Du solltest mysql-async und oxmysql deshalb nie gleichzeitig starten, sondern mysql-async aus der server.cfg entfernen.

In den betroffenen Resources ersetzt du im Manifest @mysql-async/lib/MySQL.lua durch @oxmysql/lib/MySQL.lua. Für neuen oder überarbeiteten Code lohnt sich die Umstellung auf die aktuellen Funktionsnamen:

  • MySQL.Async.fetchAll wird zu MySQL.query
  • MySQL.Async.fetchScalar wird zu MySQL.scalar
  • MySQL.Async.execute wird zu MySQL.update
  • MySQL.Async.insert wird zu MySQL.insert
  • MySQL.Sync.fetchAll wird zu MySQL.query.await

Benannte Platzhalter im Stil @identifier mit einer Lua-Tabelle wie { ['@identifier'] = id } funktionieren weiterhin. Bei der Umstellung ist das ein guter Moment, alle Stellen zu suchen, an denen noch Strings verkettet werden.

Typische Fehlermeldungen und ihre Ursache

Die Fehler von oxmysql stammen meist direkt vom Datenbanktreiber. Der Code am Anfang der Meldung verrät fast immer die Ursache:

  • ECONNREFUSED: Der Datenbankserver läuft nicht, lauscht auf einem anderen Port oder nur auf einer anderen Adresse. Prüfe Dienststatus, Port und die Bind-Adresse in der Datenbank-Konfiguration.
  • ER_ACCESS_DENIED_ERROR: Benutzer oder Passwort falsch, oder der Host passt nicht. In MySQL sind 'fivem'@'localhost' und 'fivem'@'127.0.0.1' zwei verschiedene Konten, weil localhost oft über den Socket statt über TCP verbindet. Der Host im Connection-String muss zum angelegten Konto passen.
  • ER_BAD_DB_ERROR: Die Datenbank im Connection-String existiert nicht oder ist falsch geschrieben.
  • ER_NO_SUCH_TABLE: Die SQL-Datei eines Scripts wurde nicht importiert.
  • attempt to index a nil value (global 'MySQL'): Die Lua-Bibliothek fehlt im fxmanifest.lua, oder die Resource startet vor oxmysql.

Ein Sonderfall ist ein Passwort mit Sonderzeichen in der URI-Schreibweise. Dann meldet oxmysql oft einen Zugriffsfehler, obwohl das Passwort im Datenbank-Client funktioniert. Teste in diesem Fall die Semikolon-Schreibweise, bevor du den Benutzer neu anlegst.

Langsame Queries mit oxmysql erkennen

oxmysql warnt in der Konsole, wenn eine Abfrage länger dauert als ein Schwellenwert, den du über die Convar mysql_slow_query_warning in Millisekunden festlegst. Für die Fehlersuche kannst du zusätzlich mysql_debug aktivieren, das alle Queries protokolliert. Im Live-Betrieb lässt du Debug wieder aus, weil die Konsole sonst unlesbar wird.

set mysql_slow_query_warning 150
# nur zur Fehlersuche:
# set mysql_debug true

Taucht dieselbe Query immer wieder in den Warnungen auf, fehlt meist ein Index auf der Spalte im WHERE. Mit EXPLAIN vor der Query siehst du, ob die Datenbank die ganze Tabelle durchsucht. Ein Index auf Besitzerspalten von Fahrzeug- oder Inventartabellen hilft bei wachsendem Datenbestand spürbar:

EXPLAIN SELECT * FROM owned_vehicles WHERE owner = 'char1:abc123';
ALTER TABLE owned_vehicles ADD INDEX idx_owner (owner);

Ebenso wichtig ist, wann Queries laufen. Abfragen in einer Schleife pro Tick oder pro Spieler im Sekundentakt belasten die Datenbank unnötig. Lade Daten beim Login, halte sie im Speicher und schreibe Änderungen gezielt zurück.

Datenbank im Betrieb sichern und verwalten

Sobald oxmysql läuft, liegt der komplette Spielstand in der Datenbank: Charaktere, Konten, Fahrzeuge, Inventare. Ein regelmäßiges Backup, das nicht nur auf demselben Server liegt, gehört deshalb direkt zur Einrichtung. Das geht mit einem Cronjob und mysqldump ebenso wie mit fertigen Werkzeugen.

Bei Web-Services gibt es dafür etwa den DB Backup Bot, der mehrere Datenbanken zeitgesteuert sichert und die Backups in einen Discord-Channel sowie in einen Ordner auf dem Server ablegt. Wer Spieler, Wirtschaft, Jobs und Items lieber über eine Weboberfläche statt per SQL-Client pflegt, kann sich das Game Control Panel mit Live-Bridge zum laufenden Server ansehen, das auch einen Free-Plan hat. Beides ersetzt nicht das Verständnis der Datenbank, nimmt aber wiederkehrende Handarbeit ab. Für Protokolle über Datenbankänderungen bietet sich zusätzlich ein Discord-Webhook mit Rate-Limit-Queue an.

FAQ

Muss oxmysql vor ESX, QBCore oder QBox starten?

Ja. Das Framework greift beim Start auf die Datenbank zu, deshalb muss ensure oxmysql in der server.cfg vor es_extended, qb-core oder qbx_core stehen. Gleiches gilt für jedes Script, das oxmysql nutzt.

Funktioniert oxmysql mit MariaDB?

Ja, oxmysql arbeitet sowohl mit MySQL als auch mit MariaDB. Wichtiger als die Wahl des Datenbankservers sind ein Zeichensatz mit utf8mb4 und ein eigener Benutzer mit Rechten nur auf die FiveM-Datenbank.

Kann ich mysql-async und oxmysql parallel betreiben?

Das solltest du nicht tun. oxmysql übernimmt die Rolle von mysql-async und stellt die alten Aufrufe über eine Kompatibilitätsschicht bereit. Entferne mysql-async aus der server.cfg und passe in älteren Resources den Bibliothekspfad im Manifest an.

Warum verbindet sich oxmysql nicht, obwohl die Zugangsdaten stimmen?

Häufig liegt es an Sonderzeichen im Passwort, die in der URI-Schreibweise nicht kodiert sind, oder an einem Host-Unterschied zwischen localhost und 127.0.0.1 beim Datenbank-Benutzer. Prüfe außerdem, ob der Datenbankserver auf dem angegebenen Port erreichbar ist und die Convar mit set geladen wird.

Anmelden

FAQ

Du bekommst Hilfe bei Fragen oder der Einrichtung unserer Produkte auf unserem Discord (discord.gg/webservices).

Du kannst das gekaufte Skript wie gewohnt von deinem Keymaster-Konto herunterladen und dann auf deinem Server verwenden.

Leider ist eine Rückerstattung nicht möglich.

Du kannst unser Control Panel über den folgenden Link erreichen: control-panel.ws

Alle Rechte vorbehalten. 2021-2026 © WS Shop
Nutzungsbedingungen
Datenschutz
Impressum
Gestaltet von: Mattiwe Design