--- title: "How to Enable the MySQL Module in AMX Mod X" excerpt: "Enable the MySQL/SQLx module in AMX Mod X, configure sql.cfg, use threaded queries, and fix the connection errors that actually happen." category: "installation" tags: "amxmodx, mysql" image: "" read_time: "9 min read" ---

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:

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 threaded SQLx queries.

Common errors

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.