Fix: Server Freezes When a Plugin Queries MySQL (Blocking Queries)

March 12, 2026 Daemon666 8 min read 7 vues

Every time a particular plugin talks to MySQL — a player connects and it loads their VIP status, someone types a command that reads the database — the entire server freezes for a moment: everyone lags, then it resumes. This is not a network problem and not the database being slow in isolation; it is a plugin running a blocking query on the main game thread. GoldSrc is single-threaded, so while the engine waits for MySQL to answer, it cannot simulate anything else. Here is why it happens and how to fix it properly.

1. Understand the single-threaded stall

The CS 1.6 engine runs the game world on one thread. When a plugin calls a blocking SQL function, that thread stops and waits for the database round-trip to complete. If the database is on another host, or under load, or the query is slow, that wait can be tens or hundreds of milliseconds — and for that entire time nothing moves in game. The freeze length equals the query time. A fast local query barely shows; a slow or remote one produces a visible, whole-server hitch.

2. Know the two SQLX query styles

The AMX Mod X sqlx module offers two ways to run a query, and the difference is the whole issue:

  • BlockingSQL_Execute on a prepared query runs on the main thread and the engine waits. Simple to write, but it freezes the server for the query's duration.
  • ThreadedSQL_ThreadQuery hands the query to a background thread and calls your handler when the result is ready, without stalling the game. This is the correct choice for anything touching a networked or non-trivial database.

A plugin that uses blocking queries in a per-player or per-command path is the classic cause of the freeze. The fix is to use threaded queries.

3. Convert to threaded queries

The threaded pattern registers a callback that receives the result later. In Pawn it looks like this:

SQL_ThreadQuery(g_hTuple, "query_handler", "SELECT flags FROM vips WHERE steamid = '%s'", steamid)

public query_handler(failstate, Handle:query, error[], errcode, data[], size, Float:queuetime) {
    if (failstate != TQUERY_SUCCESS) {
        log_amx("SQL error %d: %s", errcode, error)
        return
    }
    // read rows from query here, no server freeze
}

The engine keeps simulating while MySQL works, and your handler runs when the answer arrives. If you wrote the plugin, replace every SQL_Execute in a gameplay path with SQL_ThreadQuery. If it is a third-party plugin, this is why it freezes and why you should replace it with one that uses threaded queries — a maintained plugin such as the CSB VIP Core does its database work off the main thread.

4. Reduce the query cost too

Threading hides the latency but does not excuse a bad schema. Make the queries cheap so even the background thread returns fast and connections do not pile up:

  • Index the columns you filter on — a SELECT ... WHERE steamid = ? against an unindexed column scans the whole table.
  • Cache per-player data in memory on connect and write back on disconnect, rather than querying every action.
  • Keep the database close — a MySQL host across the internet turns every query into a slow round-trip. Run it on the same box or LAN.

5. Find which plugin is doing it

If you do not know which plugin freezes the server, correlate the hitch with events. The freeze on player connect points at a plugin loading data on connect; on a chat command points at that command's handler. Pause suspects one at a time and watch whether the freeze disappears:

amxx pause suspect.amxx

When the freeze stops after pausing a specific plugin, that plugin's blocking query is the cause. The same pausing technique isolates FPS-draining plugins in the server FPS guide.

Troubleshooting

  • Freeze exactly when a player connects — a plugin runs a blocking query on connect. Convert it to SQL_ThreadQuery.
  • Freeze on a specific chat command — that command's handler blocks on SQL. Thread it or cache the data.
  • Freezes got worse over time — the table grew and unindexed queries got slower. Add indexes.
  • Freezes only when the DB is remote — network latency per query. Move MySQL local or cache aggressively.
  • SQL error in logs plus a hang — the plugin is retrying a failing blocking query, stalling each time. Fix the connection and thread the query.
  • Intermittent long freezes under load — blocking queries queuing behind each other on the main thread. Threaded queries remove the serialization.

Verification

After moving the plugin to threaded queries, reproduce the trigger — have players connect rapidly, or spam the command — while watching stats in the console. The server FPS should stay steady with no hitch, because the main thread never waits on MySQL. Confirm the data still loads correctly (VIP flags apply, stats save) proving the threaded handler runs. If the freeze is gone and the data is right, the conversion worked. If a residual freeze remains, another plugin still uses blocking queries — pause them one at a time until the last hitch disappears.

Contributeurs: Daemon666 ✦
Partager :