News

Mask Query Bindings in Laravel Exception Messages

Published
Mask Query Bindings in Laravel Exception Messages image

When a query fails, Laravel builds a QueryException whose message contains the SQL with every bound value interpolated into it. That is deliberate. A message reading SQL: insert into "users" ("email") values (?) tells you almost nothing about which row broke, while the version with the value tells you immediately.

The problem is that the message does not stay where you can see it. It is a string on an exception, and exceptions get written down.

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'ada@example.com' for key 'users_email_unique' (Connection: mysql, Host: 10.0.4.17, Port: 3306, Database: platform, SQL: insert into `users` (`email`, `name`, `national_id`) values (ada@example.com, Ada Lovelace, 640312-4185))

Every value bound to that insert is now in a log line. If the query ran inside a queued job, the same string is in the exception column of your failed_jobs table, because DatabaseFailedJobProvider::log() casts the exception to a string and inserts it. If you run an APM or OpenTelemetry agent, it recorded the exception on the span. Anywhere your exception reporting sends data is now holding a copy of whatever those bindings were: email addresses, names, government identifiers, an API token being written into an integrations table.

Laravel 13.27 adds a per-connection option to stop the interpolation.

Turning It On

Set mask_bindings_in_exception_messages on the connection:

'connections' => [
'mysql' => [
'driver' => 'mysql',
// ...
'mask_bindings_in_exception_messages' => env('DB_MASK_BINDINGS', false),
],
],

The key ships in the framework's own config/database.php on all five default connections, so an application that has never published that file can turn masking on with an environment variable alone:

DB_MASK_BINDINGS=true

The message then keeps its ? placeholders:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'ada@example.com' for key 'users_email_unique' (Connection: mysql, Host: 10.0.4.17, Port: 3306, Database: platform, SQL: insert into `users` (`email`, `name`, `national_id`) values (?, ?, ?))

Further Reading

Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Filed in

Sponsored

masteringlaravel logo
Laravel Code Review

Get expert guidance in a few days with a Laravel code review

Visit Laravel Code Review

The latest

View all →
Pessimistic Locking in Laravel Eloquent with refreshForUpdate() image

Pessimistic Locking in Laravel Eloquent with refreshForUpdate()

Read article
whereBinary(): Case-Sensitive MySQL Queries in Laravel image

whereBinary(): Case-Sensitive MySQL Queries in Laravel

Read article
Compile PHP to Native Binaries with TypePHP image

Compile PHP to Native Binaries with TypePHP

Read article
State of Laravel 2026 Survey Is Now Open image

State of Laravel 2026 Survey Is Now Open

Read article
Testing Best Practices Skill in Laravel Boost v2.6.0 image

Testing Best Practices Skill in Laravel Boost v2.6.0

Read article
Query Binding Masking and whereBinary() in Laravel 13.27 image

Query Binding Masking and whereBinary() in Laravel 13.27

Read article