What's New in Laravel 13.27
Laravel 13.27 was released on August 26, 2026, bringing several developer-quality-of-life improvements alongside meaningful security and correctness fixes. Here is a breakdown of the most important changes.
Masking Query Bindings in Exception Messages
By default, QueryException interpolates bound values directly into its message. That means a failed INSERT can expose email addresses, names, or other sensitive data in log files, APM spans, and the failed_jobs table.
A new per-connection config key stops the interpolation:
'mysql' => [
'driver' => 'mysql',
// ...
'mask_bindings_in_exception_messages' => env('DB_MASK_BINDINGS', false),
],
With masking enabled, the exception message retains ? placeholders instead of real values. getBindings() is unaffected, so debugging tooling that reads bindings directly still works. Applications that never published config/database.php can enable the feature with a single environment variable: DB_MASK_BINDINGS=true.
whereBinary() for Case-Sensitive Comparisons
MySQL's default collations are case-insensitive, so where('name', 'John') also matches john and JOHN. Previously, a byte-exact comparison required raw SQL:
DB::table('queues')->whereRaw('name = BINARY ?', [$queueName])->first();
Laravel 13.27 adds a full family of query builder methods:
DB::table('queues')->whereBinary('name', $queueName)->first();
// select * from `queues` where `name` = binary ?
DB::table('queues')->whereNotBinary('name', $queueName)->get();
// select * from `queues` where `name` != binary ?
The family includes orWhereBinary() and orWhereNotBinary(). MariaDB inherits the MySQL grammar and works automatically. Postgres, SQLite, and SQL Server throw a RuntimeException, consistent with how whereLike() handles engines that are already case-sensitive.
refreshForUpdate() for Pessimistic Locking
Models resolved before a transaction starts — through route model binding or a job payload — need to be re-queried under a lock before writing. The old pattern discarded the existing instance:
DB::transaction(function () use ($product) {
$product = Product::query()->lockForUpdate()->findOrFail($product->getKey());
$product->decrement('stock');
});
The new refreshForUpdate() method refreshes the instance in place:
DB::transaction(function () use ($product) {
$product->refreshForUpdate();
if ($product->stock === 0) {
throw new RuntimeException('The product is out of stock.');
}
$product->decrement('stock');
});
The lock only holds for the life of the transaction, so the call must be made inside one.
Cloud Facade
A new Cloud facade consolidates Laravel Cloud environment checks into three methods:
use Illuminate\Support\Facades\Cloud;
Cloud::hosted(); // running on Laravel Cloud?
Cloud::usesManagedQueues(); // is the cloud queue connection configured?
Cloud::queue(); // the managed queue connection itself
Cloud::queue() throws a RuntimeException when managed queues are not configured, so pair it with usesManagedQueues(). The facade is not registered in the default aliases to avoid collisions with existing application classes.
Queue Size Totals
Three new methods sum queue sizes across every queue a connection knows about, without decoding job payloads:
Queue::totalPendingSize();
Queue::totalDelayedSize();
Queue::totalReservedSize();
Implemented for the Redis, database, failover, and fake drivers.
Other Notable Changes
- Vector distance queries now work on MariaDB 11.7+ via
vec_distance_cosine(). - Validation hardening:
in_arrayanddoesnt_containrules now use strict comparison, preventing scientific-notation string matches like"1e0"matching"1". Request::merge(['*' => value])no longer wipes the entire input array;*is now stored literally.MaintenanceModeBypassCookie::isValid()now checksis_string()on themacfield, preventing a malformed cookie from causing a 500 error.- Postgres keepalive DSN options prevent idle firewall timeouts from silently killing long-lived worker connections.
- SQS credential caching reduces AWS credential fetches to one per rotation instead of one per PHP-FPM worker.
Key Takeaways
- Enable
DB_MASK_BINDINGS=trueto keep sensitive values out of exception messages and logs. - Replace
whereRaw('name = BINARY ?', [...])withwhereBinary('name', ...)for cleaner, driver-aware code. - Use
refreshForUpdate()inside transactions to simplify pessimistic locking on already-resolved models. - The
Cloudfacade provides a clean API for Laravel Cloud environment detection. - Strict comparison fixes in validation rules close subtle type-juggling edge cases.
Source: Laravel News — Laravel 13.27.0