reap_async_query
Learn how mysqli_reap_async_query() fetches an async MySQLi query result in PHP, with a runnable parallel-query example using mysqli_poll.
Introduction
mysqli_reap_async_query() retrieves the result of a query that was started asynchronously with the MySQLi extension. An asynchronous query is one you fire off without waiting for the server to finish — your PHP script keeps running, and you collect the result later, once the server signals it is ready.
This is the missing piece of MySQLi's asynchronous workflow. On its own, mysqli_reap_async_query() does nothing useful: it only makes sense as the final step of a three-part pattern made up of mysqli_query(..., MYSQLI_ASYNC) (or mysqli_send_query()), mysqli_poll(), and mysqli_reap_async_query(). This page explains how those pieces fit together, shows a complete runnable example, and lists the gotchas that trip people up.
Requirement: asynchronous queries only work with the mysqlnd driver (the default native driver in modern PHP builds). They are not available when MySQLi is compiled against the older
libmysqlclient.
The asynchronous query lifecycle
A single asynchronous query goes through three stages:
- Send — start the query with the
MYSQLI_ASYNCflag.mysqli_query($conn, $sql, MYSQLI_RESULT, MYSQLI_ASYNC)(or the shorthandmysqli_send_query()) returns immediately without waiting for results. - Poll — call
mysqli_poll()to wait until one or more connections have a result ready. This is where you block (with a timeout you control), instead of blocking on the query itself. - Reap — once polling reports a connection is ready, call
mysqli_reap_async_query($conn)to fetch themysqli_resultfor that connection.
The reason this matters is the poll step. You can put several connections into a single mysqli_poll() call and have all their queries run on the server at the same time. The total wait becomes roughly the time of the slowest query, not the sum of all of them.
mysqli_poll(): the part you can't skip
A common mistake is to call mysqli_reap_async_query() directly after sending a query. If the result is not ready yet, reaping returns false and sets an error — it does not wait. mysqli_poll() is the function that waits.
mysqli_poll() takes arrays of connections passed by reference and a timeout:
mysqli_poll($read, $error, $reject, $sec, $usec);$read— an array of the connections you want to watch. After the call, it is trimmed to only the connections that have a result waiting.$error/$reject— receive connections with protocol errors or rejected requests.$sec/$usec— how long to wait, in seconds and microseconds.
It returns the number of ready connections (0 on timeout, false on failure).
Complete example: run two queries in parallel
The example below opens two connections, fires an async query on each, polls until results arrive, and reaps each one. Replace the credentials and SQL with your own.
<?php
// One connection per concurrent query.
$conn1 = mysqli_connect("localhost", "user", "password", "shop");
$conn2 = mysqli_connect("localhost", "user", "password", "shop");
// 1. Send both queries asynchronously — neither call blocks.
mysqli_query($conn1, "SELECT COUNT(*) AS n FROM orders", MYSQLI_STORE_RESULT, MYSQLI_ASYNC);
mysqli_query($conn2, "SELECT COUNT(*) AS n FROM customers", MYSQLI_STORE_RESULT, MYSQLI_ASYNC);
$links = [$conn1, $conn2];
$pending = count($links);
// 2. Poll until every connection has reported back.
while ($pending > 0) {
$read = $error = $reject = $links;
// Wait up to 1 second for any connection to become ready.
if (!mysqli_poll($read, $error, $reject, 1)) {
continue; // timeout — nothing ready yet, loop again
}
// 3. Reap each ready connection.
foreach ($read as $link) {
$result = mysqli_reap_async_query($link);
if ($result) {
$row = mysqli_fetch_assoc($result);
echo "Count: " . $row["n"] . "\n";
mysqli_free_result($result);
} else {
echo "Query error: " . mysqli_error($link) . "\n";
}
$pending--;
}
}
?>Each connection can only run one asynchronous query at a time — that is why the example uses a separate connection per query. Reuse a connection for a new async query only after you have reaped the previous result.
Step-by-step summary
- Open one connection per query you want to run concurrently (
mysqli_connect()). - Start each query with the
MYSQLI_ASYNCflag so the call returns immediately. - Collect the connections into an array and pass it to
mysqli_poll()with a timeout. - For every connection
mysqli_poll()reports as ready, callmysqli_reap_async_query(). - Process the returned
mysqli_result, then free it withmysqli_free_result().
Return values and error handling
mysqli_reap_async_query() returns:
- A
mysqli_resultobject for queries that produce a result set (e.g.SELECT). truefor queries that do not return rows (INSERT,UPDATE,DELETE) when they succeed.falseon failure, or when called before the result is ready — checkmysqli_error()in that case.
Always gate the reap behind mysqli_poll(). Reaping a connection that is not ready is the single most common source of mysterious false returns.
Use Cases for MySQLi Non-Blocking Queries
MySQLi non-blocking queries are useful for PHP developers who need to perform multiple queries in parallel or execute long-running queries without blocking other code execution. Here are some practical use cases for this approach:
1. Parallel Query Execution
Developers can use MySQLi non-blocking queries to execute multiple independent queries in parallel. By sending each query with mysqli_send_query() and interleaving other logic, applications can reduce overall wait times when fetching data from multiple tables or services.
2. Long-Running Queries
Long-running queries can be initiated asynchronously so the PHP script can handle other tasks, such as logging, UI updates, or processing user input, while the database completes the operation.
3. Real-Time Applications
Applications requiring frequent data polling or real-time updates can initiate queries without freezing the main execution thread. This is particularly useful for CLI-based monitoring tools or lightweight web endpoints that need to return quickly.
4. Asynchronous Data Processing
Developers can offload heavy data retrieval tasks to run in the background while the main script processes other data streams, improving overall throughput in batch processing or ETL workflows.
Advantages of MySQLi Non-Blocking Queries
MySQLi non-blocking queries offer several advantages for PHP developers:
1. Improved Performance
By executing queries asynchronously, other code execution is not blocked, resulting in faster application performance. This is especially beneficial for applications that aggregate data from multiple sources or handle high-concurrency requests.
2. Better Resource Utilization
Non-blocking execution allows the PHP process to remain responsive while waiting for database operations, reducing idle time and improving server resource utilization.
3. Simplified Background Task Management
Developers can chain multiple database operations without nesting callbacks or complex state machines, making the code easier to read and maintain for standard procedural PHP scripts.
Conclusion
mysqli_reap_async_query() is the final step of MySQLi's asynchronous query workflow: you start a query with the MYSQLI_ASYNC flag, wait for it with mysqli_poll(), and then reap the result. Used together, these functions let a PHP script run several queries against MySQL in parallel and gather the results as they finish, instead of waiting for each one in turn. The biggest payoff is when you have multiple independent queries — the total wait drops to roughly the slowest query rather than the sum of all of them. Remember the two rules that keep this reliable: one async query per connection, and never reap before mysqli_poll() says the connection is ready.
Related topics
- mysqli_poll — wait for one or more async connections to become ready.
- mysqli_multi_query — run several statements in a single call.
- mysqli_query — the standard (synchronous) query function.
- mysqli_connect — open the connections you run queries on.
- PHP MySQLi — overview of the MySQLi extension.