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.

Best practices
Illustration of organizing and querying data

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

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting