Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

saliem3651's avatar

How to Implement Queue with Custom Database in Multitenant Architecture?

Hi everyone,

I’m working on a multitenant application in Laravel where the database connection is determined dynamically based on the subdomain of the request. For example:

  • spain.example.com uses the spain_db.
  • india.example.com uses the india_db.

I’ve implemented middleware (IdentifyTenant) to detect the subdomain, fetch the tenant’s database details, and set the connection dynamically like this:

config([
    'database.connections.custom' => [
        'driver'    => 'mysql',
        'host'      => $tenantDetails['db_host'],
        'database'  => $tenantDetails['db_name'],
        'username'  => $tenantDetails['db_user'],
        'password'  => $tenantDetails['db_password'],
        'charset'   => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
        'engine'    => null,
    ],
]);
DB::setDefaultConnection('custom');

This works perfectly for HTTP requests, and the database connection is dynamically set based on the subdomain.


The Problem: Queue Workers

When I run php artisan queue:work or php artisan queue:listen, the queue worker always picks the default database from the .env file. However, in my case, I need the worker to dynamically determine the database connection based on the tenant details stored in the job.


What I’ve Tried:

  1. Passing Tenant Details in the Job Payload: I included tenant-specific details in the job when dispatching it:

    $tenantDetails = [
        'db_host' => '127.0.0.1',
        'db_name' => 'spain_db',
        'db_user' => 'root',
        'db_password' => '',
    ];
    YourJob::dispatch($tenantDetails);
    

    In the job’s handle method, I dynamically set the database:

    config([
        'database.connections.custom' => [
            'driver'    => 'mysql',
            'host'      => $this->tenantDetails['db_host'],
            'database'  => $this->tenantDetails['db_name'],
            'username'  => $this->tenantDetails['db_user'],
            'password'  => $this->tenantDetails['db_password'],
            'charset'   => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix'    => '',
            'strict'    => false,
            'engine'    => null,
        ],
    ]);
    DB::setDefaultConnection('custom');
    
  2. Using the JobProcessing Event: I created a listener for the JobProcessing event to dynamically configure the tenant database:

    And registered it in EventServiceProvider:

    use Illuminate\Queue\Events\JobProcessing;
    use App\Listeners\SetTenantForQueue;
    
    protected $listen = [
        JobProcessing::class => [
            SetTenantForQueue::class,
        ],
    ];
    

The Issue:

Despite these attempts, the worker still seems to pick the default database from the .env file when executing the job. How can I ensure that the queue worker dynamically uses the tenant database based on the subdomain or the job payload?


What I Need Help With:

  1. How can I configure Laravel’s queue worker to dynamically set the database connection for each job?
  2. Is there a better way to handle multitenant databases with queues in Laravel?
  3. How can I make the queue worker "tenant-aware" without requiring manual intervention (e.g., running separate workers for each tenant)?

I’d really appreciate any advice or best practices for handling this scenario in a multitenant architecture. Thanks in advance!

0 likes
4 replies
martinbean's avatar

@saliem3651 I think the issue will be, the database connection will have already been configured and created by the framework well before a queue worker has picked up a job for processing. Remember that there’s a database driver for queues, so a database connection will need to be in place before in order to be able to connect to the database and retrieve a job.

Personally, if you’re defining databases per tenant then I’d have a specific tenant named connection rather than trying to re-use the application’s default connection, and then specify the connection in your tenant-specific Eloquent models.

With the above approach, you could then define some sort of “tenant aware” interface, and in the event listener like you were doing, configure and create the database connection before the job is handled:

public function handle(JobProcessing $event)
{
    if (in_array(TenantAware::class, class_implements($event->job->resolveName()))) {
        $defaults = config(sprintf('database.connections.%s', config('database.default')));

        DB::connectUsing('tenant', array_merge($defaults, [
            'host' => $tenant['db_host'],
            'database' => $tenant['db_name'],
            'username' => $tenant['db_user'],
            'password' => $tenant['db_password'],
        ]));
    }
}
Ben Taylor's avatar

You could have a .env file for each database and then append --env= with the env name to the queue:work artisan command in supervisor.

E.g.

.env.india

--env=india

You would of course have to set up multiple queues with supervisor. One for each env file

saliem3651's avatar

@Ben Taylor hi but i wont to set .env file , because db detail coming from another server

Please or to participate in this conversation.