How to Enable the MySQL Module in AMX Mod X

April 1, 2026 Daemon666 9 min read 14 görüntülenme

AMX Mod X talks to MySQL through the MySQL module, which backs the sqlx include. That is what stats plugins, ban systems (AMXBans), shops and VIP systems use to persist data across map changes and across servers. Enabling it is three steps. Using it without freezing your server is the part people get wrong.

1. Enable the module

The module ships with the AMX Mod X base package but is commented out by default. Edit addons/amxmodx/configs/modules.ini:

fun
engine
fakemeta
cstrike
csx
hamsandwich
nvault
mysql

Uncomment (or add) mysql. Confirm the file exists:

ls -la /home/steam/hlds/cstrike/addons/amxmodx/modules/mysql_amxx_i386.so
file /home/steam/hlds/cstrike/addons/amxmodx/modules/mysql_amxx_i386.so

It must be ELF 32-bit LSB shared object, Intel 80386. The module statically carries what it needs to speak the MySQL wire protocol — you do not need to install a 32-bit MySQL client library on the host, and trying to is a common wild goose chase.

2. Configure sql.cfg

addons/amxmodx/configs/sql.cfg holds the default credentials that plugins pick up via get_cvar_string("amx_sql_host") and friends:

amx_sql_host     "127.0.0.1"
amx_sql_user     "amxx"
amx_sql_pass     "a-real-password"
amx_sql_db       "amxx"
amx_sql_table    "amx_amxbans"
amx_sql_type     "mysql"
amx_sql_timeout  "60"

Two things that bite:

  • 127.0.0.1 and localhost are not the same to MySQL. localhost means a Unix socket; 127.0.0.1 means TCP. Grants are per-host, so 'amxx'@'localhost' will not authenticate a TCP connection from 'amxx'@'127.0.0.1'. Use 127.0.0.1 and grant to it.
  • sql.cfg is world-readable if you are careless. It contains a plaintext database password. chmod 640 it and make sure the HLDS user owns it.

3. Create the database and user

CREATE DATABASE amxx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'amxx'@'127.0.0.1' IDENTIFIED BY 'a-real-password';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, INDEX ON amxx.* TO 'amxx'@'127.0.0.1';
FLUSH PRIVILEGES;

Do not grant ALL PRIVILEGES and do not use root. An AMXX plugin from a forum is not code you have audited; it should not be able to drop your database. If MySQL is on another host, grant to that host's IP and make sure MySQL is not listening on 0.0.0.0 without a firewall. Setup details: MariaDB for AMX Mod X.

4. Restart and verify

Modules load at startup, not at map change. Restart, then:

amxx modules
Currently loaded modules:
      name           version     author           status
 [ 6] MySQL          1.9.0.5258  AMXX Dev Team    running

Then confirm an actual connection. The cleanest test is a plugin that uses the database — install your stats or ban plugin and watch addons/amxmodx/logs/error_*.log at startup. A working connection is silent; a broken one is very loud.

5. Threaded queries, or your server will freeze

This is the single most important thing on this page. SQL_Execute() is blocking: the entire game loop stops until MySQL answers. On a healthy local socket that is a few milliseconds and you will not notice. When the database is on another host, or under load, or the network hiccups, it is 200ms — and every player on the server just froze for 200ms.

Use the threaded API instead. The pattern:

#include <amxmodx>
#include <sqlx>

new Handle:g_sqlTuple

public plugin_init()
{
    register_plugin("Example SQL", "1.0", "you")

    new host[64], user[32], pass[32], db[32]
    get_cvar_string("amx_sql_host", host, charsmax(host))
    get_cvar_string("amx_sql_user", user, charsmax(user))
    get_cvar_string("amx_sql_pass", pass, charsmax(pass))
    get_cvar_string("amx_sql_db",   db,   charsmax(db))

    g_sqlTuple = SQL_MakeDbTuple(host, user, pass, db)

    SQL_ThreadQuery(g_sqlTuple, "QueryHandler",
        "CREATE TABLE IF NOT EXISTS players (steamid VARCHAR(32) PRIMARY KEY, points INT DEFAULT 0)")
}

public QueryHandler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime)
{
    if (failstate != TQUERY_SUCCESS)
    {
        log_amx("SQL error %d: %s", errnum, error)
        return
    }
    // read rows here with SQL_ReadResult / SQL_MoreResults
}

The rules: build the tuple once in plugin_init(), never inside a per-frame or per-spawn handler; always check failstate; never call SQL_FreeHandle() on a handle you did not create in that callback. Getting the last one wrong crashes the server — see crash in SQLx threaded queries.

Common errors

  • Access denied for user 'amxx'@'localhost' (using password: YES) — the grant does not match the host MySQL sees you coming from. Grant to 'amxx'@'127.0.0.1' and set amx_sql_host to 127.0.0.1. Full walkthrough: Access denied from an AMXX plugin.
  • Can't connect to MySQL server on '10.0.0.5' (111) — errno 111 is connection refused: MySQL is bound to 127.0.0.1 only, or a firewall is dropping 3306. See errno 111.
  • Module failed to load for mysql — the .so is missing from modules/, or it is 64-bit. Reinstall from the AMXX base package for your exact version.
  • Server stutters every round — a plugin using SQL_Execute() on a hot path. Convert it to SQL_ThreadQuery(); see server freezes on MySQL query.
  • Unknown database 'amxx' — the database name in sql.cfg does not exist. Case matters on Linux.

Verification checklist

  1. amxx modules shows MySQL as running.
  2. Your stats/bans plugin creates its tables — check with SHOW TABLES; in the database.
  3. A ban issued in-game appears as a row in MySQL.
  4. Data survives a map change and a server restart.
  5. error_*.log has no SQL lines after a full map.
Katkıda bulunanlar: Daemon666 ✦
Paylaş: