Laravel
multiple databases
database connections
Laravel tutorial
web development

How to use multiple databases in Laravel

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Laravel supports more than one database connection out of the box, which is useful for reporting databases, tenant-specific databases, legacy systems, or read and write separation. The important part is not only defining the extra connections, but also making sure each query, model, migration, and transaction is pointed at the correct one.

Define Multiple Connections

Laravel stores connection definitions in config/database.php. You can add as many named connections as your application needs.

php
1'connections' => [
2    'mysql' => [
3        'driver' => 'mysql',
4        'host' => env('DB_HOST', '127.0.0.1'),
5        'port' => env('DB_PORT', '3306'),
6        'database' => env('DB_DATABASE', 'app'),
7        'username' => env('DB_USERNAME', 'root'),
8        'password' => env('DB_PASSWORD', ''),
9        'charset' => 'utf8mb4',
10        'collation' => 'utf8mb4_unicode_ci',
11    ],
12
13    'reporting' => [
14        'driver' => 'mysql',
15        'host' => env('REPORTING_DB_HOST', '127.0.0.1'),
16        'port' => env('REPORTING_DB_PORT', '3306'),
17        'database' => env('REPORTING_DB_DATABASE', 'reporting'),
18        'username' => env('REPORTING_DB_USERNAME', 'root'),
19        'password' => env('REPORTING_DB_PASSWORD', ''),
20        'charset' => 'utf8mb4',
21        'collation' => 'utf8mb4_unicode_ci',
22    ],
23],

Then define the matching values in .env:

env
1DB_CONNECTION=mysql
2DB_HOST=127.0.0.1
3DB_PORT=3306
4DB_DATABASE=app
5DB_USERNAME=root
6DB_PASSWORD=secret
7
8REPORTING_DB_HOST=127.0.0.1
9REPORTING_DB_PORT=3306
10REPORTING_DB_DATABASE=reporting
11REPORTING_DB_USERNAME=report_user
12REPORTING_DB_PASSWORD=secret

Laravel’s DB::connection('name') API uses these names directly, so clear naming helps a lot.

Run Queries on a Specific Connection

For one-off queries, call connection() on the DB facade:

php
1use Illuminate\Support\Facades\DB;
2
3$orders = DB::connection('reporting')
4    ->table('daily_orders')
5    ->whereDate('created_at', now()->toDateString())
6    ->get();

This keeps the default connection unchanged while routing just that query to the reporting database.

If you need the raw PDO connection, Laravel also exposes it:

php
$pdo = DB::connection('reporting')->getPdo();

That can help when integrating with a library that expects a PDO handle, though it is usually better to stay inside Laravel’s query builder or Eloquent when possible.

Bind an Eloquent Model to Another Database

If a model always belongs to a non-default database, set the $connection property on the model.

php
1<?php
2
3namespace App\Models;
4
5use Illuminate\Database\Eloquent\Model;
6
7class AuditLog extends Model
8{
9    protected $connection = 'reporting';
10    protected $table = 'audit_logs';
11}

After that, Eloquent queries for AuditLog automatically use the reporting connection:

php
1$recentLogs = AuditLog::query()
2    ->latest()
3    ->limit(20)
4    ->get();

This is cleaner than repeating DB::connection('reporting') throughout the codebase.

Migrations and Schema Operations

When a schema change belongs to a specific database, scope the migration or schema call explicitly.

From the command line:

bash
php artisan migrate --database=reporting

Inside application code:

php
1use Illuminate\Support\Facades\Schema;
2
3Schema::connection('reporting')->create('audit_logs', function ($table) {
4    $table->id();
5    $table->string('event_name');
6    $table->timestamp('created_at');
7});

Be deliberate here. It is easy to run a migration on the default database by accident and not notice until much later.

Dynamic Connections for Tenant-Like Cases

Some applications build a connection at runtime. A common example is a per-tenant database. Laravel lets you inject connection settings dynamically:

php
1config([
2    'database.connections.tenant' => [
3        'driver' => 'mysql',
4        'host' => $tenant->db_host,
5        'port' => $tenant->db_port,
6        'database' => $tenant->db_name,
7        'username' => $tenant->db_user,
8        'password' => $tenant->db_password,
9        'charset' => 'utf8mb4',
10        'collation' => 'utf8mb4_unicode_ci',
11    ],
12]);
13
14DB::purge('tenant');
15DB::reconnect('tenant');

That pattern is powerful, but it raises the bar for testing, error handling, and connection lifecycle management.

Common Pitfalls

The most common mistake is assuming that switching connections for one query also switches it for related models. It does not. A model without a $connection property still uses the default connection.

Another issue is cached configuration. If you change .env or config/database.php and Laravel still seems to use old values, clear and rebuild config cache with commands such as php artisan config:clear or php artisan config:cache.

Transactions are another trap. A transaction started on one connection does not automatically include operations on another connection. If you write to two databases in one request, you need to handle consistency deliberately because Laravel is not giving you a distributed transaction.

Finally, do not mix unrelated concerns in one connection name. Names such as mysql2 work, but names like reporting, tenant, or legacy communicate intent much better.

Summary

  • Define each database connection in config/database.php and back it with environment variables.
  • Use DB::connection('name') for query-level routing.
  • Set a model’s $connection property when it always belongs to a non-default database.
  • Scope migrations and schema changes to the correct database explicitly.
  • Be careful with config caching, cross-database consistency, and runtime-generated connections.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.