Built-in Clients
Parallel queries need a non-blocking database client. PDO has none, and the PHP extensions that do (mysqli, pgsql) are often disabled on shared hosting, and there is no such extension at all for SQL Server. So MikoORM includes its own clients for the MySQL, PostgreSQL and SQL Server (TDS) wire protocols, written in plain PHP. With them, async queries run in parallel without installing anything.
Which client is used
| Database | auto (default) | extension | php |
|---|---|---|---|
| MySQL / MariaDB | mysqli if loaded, otherwise built-in | mysqli only (one by one without it) | built-in |
| PostgreSQL | pgsql if loaded, otherwise built-in | pgsql only | built-in |
| SQL Server | built-in TDS client | one by one on the main connection | built-in |
Choose per driver with the mysql_driver, pgsql_driver and sqlsrv_driver settings (DB_ASYNC_MYSQL_DRIVER ... in .env, or Async::configure([...])). The normal (sync) queries always use PDO.
The clients need only PHP's stream sockets, plus openssl for encrypted connections and mbstring for SQL Server.
Same results as PDO
The clients convert values the way the PDO drivers do, so a query returns identical rows whether it ran sync or async:
| MySQL / MariaDB | PostgreSQL | SQL Server | |
|---|---|---|---|
| Integers | int (ZEROFILL columns stay strings, unsigned BIGINT above PHP_INT_MAX stays a string) | int / bigint as int | int as int; bigint as string |
| Decimals | string | string | string (ODBC format, e.g. .50) |
| Floats | float | float | float |
| Booleans | int (BIT(1) as int) | bool | int |
| Binary | string | bytea decoded to bytes | string |
| Dates | Y-m-d H:i:s text | text | ODBC text (Y-m-d H:i:s.mmm) |
Errors carry the same driver code and SQLSTATE (isDuplicateEntry(), isForeignKeyError() ... work the same). Speed is on par with the extensions: in local measurements 50,000 PostgreSQL rows took 115 ms with the built-in client and 117 ms with pgsql.
MySQL / MariaDB
| Feature | Support |
|---|---|
| Authentication | mysql_native_password, caching_sha2_password (MySQL 8 default, fast and full authentication; RSA key exchange without SSL), sha256_password, mysql_clear_password (TLS or Unix socket only), auth switch |
| Encryption | TLS from the usual PDO options: PDO::MYSQL_ATTR_SSL_CA, SSL_CERT, SSL_KEY, SSL_CAPATH, SSL_CIPHER, SSL_VERIFY_SERVER_CERT |
| Connection | host / port or unix_socket, connect_timeout |
| Session | the same INIT_COMMAND as PDO (SET NAMES, timeouts, lc_time_names) |
| Charsets | utf8mb4, utf8 / utf8mb3, latin1, ascii (others use mysqli or run one by one) |
| Values | inlined as escaped literals for the connection charset; NO_BACKSLASH_ESCAPES honoured |
| Cancel | KILL QUERY through the main connection |
| Stored procedures | CALL works; extra result sets are read and dropped |
$connection = ConnectionFactory::make([
'driver' => 'mysql', 'host' => 'db.example.com', 'database' => 'app',
'username' => 'app', 'password' => 'secret',
'options' => [PDO::MYSQL_ATTR_SSL_CA => '/etc/ssl/certs/db-ca.pem'], // PDO and async connections
]);
MariaDB users that only allow auth_gssapi_client / unix_socket plugin logins need mysqli.
PostgreSQL
| Feature | Support |
|---|---|
| Authentication | scram-sha-256 (the server signature is checked), md5, password |
| Encryption | sslmode: prefer (default, like libpq; PGSSLMODE is read too), require, verify-ca, verify-full, allow, disable; sslrootcert, sslcert, sslkey |
| Connection | TCP, or a Unix socket when host starts with / ('host' => '/var/run/postgresql') |
| Values | real bound parameters (extended query protocol) |
| Cancel | PostgreSQL cancel request on a second connection |
$connection = ConnectionFactory::make([
'driver' => 'pgsql', 'host' => 'db.example.com', 'database' => 'app',
'username' => 'app', 'password' => 'secret',
'sslmode' => 'verify-full', 'sslrootcert' => '/etc/ssl/certs/db-ca.pem',
]);
The SSL keys are also added to the PDO DSN, so sync and async connections use the same settings.
SQL Server
| Feature | Support |
|---|---|
| Protocol | TDS 7.4 (SQL Server 2012 and newer, Azure SQL) |
| Authentication | SQL Server logins (username / password); not Windows / Kerberos authentication |
| Encryption | like the ODBC driver: encrypt => true encrypts everything, without it only the login is encrypted; trust_server_certificate => true for self-signed certificates |
| Server address | host + port, host,port, host\instance (SQL Browser lookup), Azure gateway redirects |
| Values | real parameters via sp_executesql |
| Text | nvarchar as UTF-8; varchar / text converted from the column's code page (Turkish_CI_AS = CP1254 ...) |
| Cancel | TDS attention |
| Not read by the client | sql_variant and CLR types (geography, geometry, hierarchyid): such results are read again on the main connection, so the query still works |
$connection = ConnectionFactory::make([
'driver' => 'sqlsrv', 'host' => 'sql.example.com', 'port' => 1433, 'database' => 'app',
'username' => 'app', 'password' => 'secret',
'encrypt' => true, 'trust_server_certificate' => false,
]);
The sync queries still need pdo_sqlsrv and an ODBC driver; only the async queries use the built-in client.
SQLite
SQLite is a file, not a server: there is nothing to run queries in parallel on. Async methods there run one by one on the main connection and return the same results, so code written with ...Async() works on every database.
Troubleshooting
| Symptom | Cause / fix |
|---|---|
DB::supportsParallelQueries() is false | SQLite; enabled = false; SQL Server without username or without mbstring; MySQL charset not supported and no mysqli |
Queries correct but not faster, Log/connection.log shows "Async connection failed" | the extra connection could not be opened (connection limit, firewall, login plugin); queries ran on the main connection |
AsyncTimeoutException (SQLSTATE HYT00) | the timeout setting cancelled the query |
TLS errors with sslmode=verify-full / encrypt | check the CA file (sslrootcert, PDO::MYSQL_ATTR_SSL_CA) or use trust_server_certificate for test servers |
Force one client to compare: Async::configure(['pgsql_driver' => 'php']) or 'extension'.