W3docs

A Comprehensive Guide on mysqli_thread_safe Function in PHP

When it comes to working with MySQL databases in PHP, the mysqli extension provides a variety of functions to perform various operations. One such function is

When working with MySQL databases in PHP through the mysqli extension, a question that comes up often is: "Is mysqli thread-safe, and is there a mysqli_thread_safe() function I can call to check?"

The short answer is that mysqli_thread_safe() is not a function in PHP, and thread safety is not something you query at runtime. It is a property of how your PHP binary was built. This guide explains what "thread-safe" actually means for PHP, why mysqli thread safety is a compile-time decision, when it matters in practice, and how to verify it in your environment.

What "Thread-Safe" Means in PHP

A program is thread-safe when multiple threads can run the same code at the same time without corrupting shared data. In a thread-safe build, the PHP engine guards internal global state (the symbol table, memory manager, extension globals, etc.) so that two threads executing inside the same process cannot trample each other's data.

PHP ships in two flavors, decided when the binary is compiled:

  • ZTS (Zend Thread Safety) — also called a Thread Safe (TS) build. The engine adds locking and per-thread copies of global state so PHP can run inside a multi-threaded host process.
  • NTS (Non-Thread-Safe) — the engine assumes one request per process and skips that overhead, so it runs faster.

You cannot switch between them at runtime, and there is no mysqli_thread_safe() to toggle or report it. The build type is fixed when ./configure --enable-maintainer-zts (or the platform equivalent) is chosen during compilation.

Why It Is a Compile-Time Setting, Not a Function

People expect a mysqli_thread_safe() function because some C libraries expose a mysql_thread_safe() call. PHP does not surface one, because the answer never changes for a given binary — querying it at runtime would always return the same value. Whether mysqli is safe in threads is inherited directly from the ZTS/NTS choice baked into the PHP build, plus the underlying client library (modern PHP uses mysqlnd, the native driver, which has no separate thread-safety toggle of its own).

So instead of calling a function, you inspect the build.

When Thread Safety Actually Matters

For the vast majority of PHP applications, you should use the NTS build and thread safety is a non-issue:

SetupBuild to useWhy
Nginx + PHP-FPMNTSEach worker is a single-threaded process; no shared threads.
Apache with mpr_preforkNTSEach request gets its own process.
CLI scripts, cron jobsNTSOne process, one thread.
Apache with worker / event MPM + mod_phpZTSmod_php runs inside Apache's threaded workers.
ext like parallel / pthreads (legacy)ZTSThey spawn PHP threads in one process.

The classic real-world trap is Apache + mod_php on a threaded MPM: if you load a non-thread-safe PHP into a threaded Apache, the server can crash or corrupt data under load. Using PHP-FPM instead of mod_php sidesteps this entirely, which is why FPM + NTS is the standard modern deployment. See the PHP installation guide for how builds are chosen.

Handling mysqli in a Multi-Threaded Context

Even on a correctly built ZTS PHP, the mysqli connection object itself is not meant to be shared between threads. A mysqli link holds buffered results, prepared-statement state, and an open socket — concurrent use from two threads produces commands-out-of-sync errors or garbage results.

The rule is simple: one connection per thread. Open the connection inside the thread that uses it rather than passing a shared handle around.

<?php
// Each worker/thread creates and owns its own connection.
function runWorkerTask(int $workerId): void
{
    // New, independent connection for THIS thread.
    $db = new mysqli('localhost', 'user', 'password', 'shop');

    if ($db->connect_errno) {
        // Handle per-thread connection failure locally.
        error_log("Worker {$workerId} failed: {$db->connect_error}");
        return;
    }

    $result = $db->query('SELECT COUNT(*) AS total FROM orders');
    $row = $result->fetch_assoc();
    echo "Worker {$workerId} sees {$row['total']} orders\n";

    $db->close(); // Release the connection when the thread is done.
}

For the basics of opening and checking a connection, see Connect to MySQL with mysqli and mysqli_connect_errno().

How to Verify Thread Safety in Your Environment

Because there is no runtime function, use one of these to read the build setting.

Using phpinfo()

Create a one-line script and open it in the browser, or run it from the CLI:

<?php
phpinfo();

In the output, find the top table and look at the Thread Safety row (it sits near the Zend Engine / build information). It reads either enabled (ZTS) or disabled (NTS).

Command-Line Verification

From a terminal, filter the full configuration dump:

php -i | grep "Thread Safety"

This prints one of:

Thread Safety => enabled
Thread Safety => disabled

Inside Running PHP Code

If you want the value programmatically — for a diagnostics page, for example — read the PHP_ZTS constant instead of looking for a non-existent function:

<?php
// PHP_ZTS is 1 on a Thread Safe (ZTS) build, 0 on a Non-Thread-Safe (NTS) build.
echo PHP_ZTS === 1 ? "Thread-safe (ZTS) build\n" : "Non-thread-safe (NTS) build\n";

This is the correct, supported replacement for the imaginary mysqli_thread_safe() call.

Common Mistakes

  • Calling mysqli_thread_safe() — it does not exist and throws an Error: Call to undefined function. Use PHP_ZTS or phpinfo() instead.
  • Sharing one mysqli connection across threads — always open a separate connection per thread.
  • Loading an NTS PHP into a threaded Apache MPM — match the build to the server, or move to PHP-FPM.
  • Assuming ZTS is "better" — it is slower and only needed for genuinely threaded hosts; prefer NTS otherwise.

Conclusion

mysqli_thread_safe() is a function that does not exist. Thread safety in PHP is fixed at compile time by the Zend Thread Safety (ZTS) choice, not toggled or reported by a runtime call. Most modern stacks (Nginx/Apache-prefork + PHP-FPM) use the faster NTS build and never need ZTS. When you do need to check, read it with phpinfo(), php -i | grep "Thread Safety", or the PHP_ZTS constant — and always give each thread its own mysqli connection to keep data consistent.

Practice

Practice
What does it mean for PHP to be thread-safe?
What does it mean for PHP to be thread-safe?
Was this page helpful?