Inspect the SQL executed by Laravel
Use Laravel query logs, QueryExecuted listeners, and query-builder inspection to debug SQL while keeping bindings and long-lived worker memory under control.
Use the connection's query log for a small debugging session, DB::listen() to observe executed queries, or a builder's toSql() method to inspect a statement without executing it. The examples below target Laravel 12.x; check API availability in older applications.
Capture a short query log
use App\Models\User;
use Illuminate\Support\Facades\DB;
DB::enableQueryLog();
try {
$users = User::where('active', 1)->get();
dump(DB::getQueryLog());
} finally {
DB::disableQueryLog();
DB::flushQueryLog();
}
Each entry contains SQL with placeholders, bindings, and duration in milliseconds. Enable logging before executing the operation. Logs are connection-specific: if the model uses another connection, enable and read that connection's log with DB::connection('name').
Do not leave this enabled in long-lived queue workers or Octane processes. Entries accumulate in memory until cleared. The example turns logging off and clears it after a bounded local investigation; restore any intentionally pre-existing logging state if integrating into a larger diagnostic tool.
Listen to executed queries
Register a listener once, for example in AppServiceProvider::boot():
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
if (app()->environment('local')) {
DB::listen(function (QueryExecuted $query) {
Log::debug($query->sql, [
'time_ms' => $query->time,
// Omit bindings unless their contents have been reviewed.
]);
});
}
This observes queries passing through Laravel's database layer, not driver calls that bypass it. Repeated statements can point to an N+1 problem, but inspect the calling code before deciding they are redundant. Even SQL text without separately logged bindings can contain sensitive values when raw SQL is used.
Inspect a builder without running it
$query = User::where('active', 1)->orderBy('created_at');
dump($query->toSql());
dump($query->getBindings());
// Local debugging only; values become visible in the output.
$query->dumpRawSql();
toSql() returns the generated SQL without executing the query. Prepared statements and bindings are normally separate; a readable expanded string is a debugging representation, not necessarily what the database received as one string.
Where supported, builders and QueryExecuted events expose toRawSql(). Entries returned by getQueryLog() are arrays and have no such method. Avoid hand-written vsprintf or question-mark substitution, which can mishandle quoting and values.
Use a request-level debugging interface
Laravel Telescope's query watcher records selected queries and timings after installation, migrations, and configuration. Protect its dashboard, configure filters and retention, and review parameter exposure. Third-party Laravel Debugbar offers a development-oriented view inside the page. Neither should be exposed publicly as an unrestricted query browser.
For ongoing production diagnosis, use an appropriately scoped slow-query log or application performance monitoring rather than retaining every query in application memory.
References: Laravel database events, query-builder debugging, and Telescope query watcher.
Related reading
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan