A Comprehensive Guide on mysqli_sqlstate Function in PHP
Learn how mysqli_sqlstate() returns ANSI/ISO SQLSTATE codes in PHP, how it differs from mysqli_errno(), common codes, and exception-mode usage.
When you work with MySQL in PHP through the mysqli extension, you need a reliable way to find out why a query failed. The mysqli_sqlstate() function returns the SQLSTATE error code for the most recently executed MySQL operation — a standardized, portable code that tells you the category of an error.
This guide explains what SQLSTATE is, how mysqli_sqlstate() differs from the MySQL-specific mysqli_errno(), the codes you'll meet most often, and how to use it correctly (including in PHP's modern exception-based mode).
What is SQLSTATE?
SQLSTATE is a five-character error code defined by the ANSI/ISO SQL standard. Because it is part of the standard rather than a MySQL invention, the same code means roughly the same thing across different database engines, which makes it more portable than vendor-specific error numbers.
The five characters are split into two parts:
- The first two characters are the class of the error. For example, class
00means success,01means a warning, and42means a syntax or access-rule violation. - The last three characters are the subclass, which narrows the problem down further.
So 42S02 ("base table or view not found") belongs to class 42 (syntax/access violation) with subclass S02.
Syntax
mysqli_sqlstate(mysqli $connection): stringmysqli_sqlstate() takes a single argument — the connection object returned by mysqli_connect() — and returns a string:
- An empty-but-zero-filled string
"00000"when the last operation succeeded. - A five-character code such as
"42S02"when an error occurred.
In object-oriented style this is the method
$connection->sqlstate.
SQLSTATE vs. mysqli_errno: which should you use?
These two functions answer different questions, and you often want both:
| Function | Returns | Nature |
|---|---|---|
mysqli_sqlstate() | A 5-character string like "42S02" | ANSI/ISO standard — portable across databases |
mysqli_errno() | An integer like 1146 | MySQL-specific — more granular, but not portable |
mysqli_error() | A human-readable message | The descriptive text for logging/debugging |
Rule of thumb: branch your logic on mysqli_sqlstate() when you want code that survives a database migration, and reach for mysqli_errno() when you need a MySQL-specific distinction. Use mysqli_error() for the message you log.
A complete example
The snippet below connects, runs a query against a table that does not exist, and prints all three diagnostics so you can see how they line up:
<?php
$connection = mysqli_connect('localhost', 'user', 'password', 'mydatabase');
if (!$connection) {
die('Connection failed: ' . mysqli_connect_error());
}
$sql = "SELECT * FROM table_that_does_not_exist";
if (mysqli_query($connection, $sql)) {
echo "Query executed successfully.";
} else {
echo "SQLSTATE: " . mysqli_sqlstate($connection) . "\n";
echo "Errno: " . mysqli_errno($connection) . "\n";
echo "Message: " . mysqli_error($connection) . "\n";
}
// Typical output:
// SQLSTATE: 42S02
// Errno: 1146
// Message: Table 'mydatabase.table_that_does_not_exist' doesn't existNotice how the portable SQLSTATE (42S02) and the MySQL-specific error number (1146) describe the same problem at two levels of detail.
Common SQLSTATE codes
These are the codes you are most likely to handle in everyday PHP/MySQL work:
| SQLSTATE | Meaning |
|---|---|
00000 | Success — no error |
23000 | Integrity constraint violation (e.g. duplicate key, foreign-key failure) |
42000 | Syntax error or access-rule violation |
42S02 | Base table or view not found |
42S22 | Column not found |
HY000 | General error (a catch-all when no specific code applies) |
08S01 | Communication / connection link failure |
Branching on these lets you react meaningfully — for instance, treating a 23000 duplicate-key error as "this record already exists" instead of a fatal failure:
<?php
$sql = "INSERT INTO users (email) VALUES ('[email protected]')";
if (!mysqli_query($connection, $sql)) {
if (mysqli_sqlstate($connection) === '23000') {
echo "That email address is already registered.";
} else {
echo "Unexpected database error: " . mysqli_error($connection);
}
}Using it with exception mode
Modern PHP (8.1+) enables MySQL error reporting by default, so a failing query throws a mysqli_sql_exception rather than returning false. In that mode you read the SQLSTATE from the exception's getSqlState() method instead of calling mysqli_sqlstate() after the fact:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
try {
$connection = mysqli_connect('localhost', 'user', 'password', 'mydatabase');
mysqli_query($connection, "SELECT * FROM missing_table");
} catch (mysqli_sql_exception $e) {
echo "SQLSTATE: " . $e->getSqlState() . "\n"; // e.g. 42S02
echo "Code: " . $e->getCode() . "\n"; // e.g. 1146
echo "Message: " . $e->getMessage();
}If you call
mysqli_sqlstate()directly after an exception has already been caught, it still works — but inside atry/catchblock, reading the code from the exception object is cleaner and avoids re-querying the connection state.
Gotchas
- It only reflects the last operation. Each new query overwrites the previous SQLSTATE. Read it immediately after the call you care about — before running anything else on the same connection.
"00000"is success, not an error. Don't treat a non-empty return as a failure; a successful operation returns the all-zero string, not"".- A failed connection has no SQLSTATE. If
mysqli_connect()itself fails there is no connection object to query, so usemysqli_connect_error()for connection problems.
Conclusion
mysqli_sqlstate() gives you the portable, standards-based SQLSTATE code for the last MySQL operation, complementing the MySQL-specific mysqli_errno() and the human-readable mysqli_error(). Branch on SQLSTATE when you want database-agnostic error handling, switch to the exception's getSqlState() when you run in PHP's default exception mode, and always read the code right after the operation it describes.