The Issues of Deploying Laravel on Dokploy: Database Connection Hell

1 1 6
calendar_today agoschedule3 min read
— Originally published at dev.to

If you’ve tried deploying a Laravel application on Dokploy (the self-hosted Heroku alternative built on Docker) and immediately ran into a wall of Database connection refused or SQLSTATE[HY000] [2002] errors, you are not alone.

It works perfectly on your local machine, but the moment it hits the server, it falls apart. Here is a real-world breakdown of the database connectivity issues we experienced, why they happened, and how to fix them.


1. The "Localhost" Trap (The 127.0.0.1 Connection Refused)

The Issue

On your local computer, you probably set your .env to:

DB_HOST=127.0.0.1
DB_PORT=3306

When you deploy this to Dokploy, your Laravel application crashes on start because it cannot connect to the database.

The Reason

Dokploy runs everything in isolated Docker Containers.
Inside a container, 127.0.0.1 or localhost refers to the Laravel container itself, not the host machine or your database container. Since there is no database running inside your Laravel code container, it refuses the connection.

The Solution

You must use Docker's internal networking.

  1. If your database is created inside Dokploy, Dokploy assigns it a specific network service name (e.g. dokploy-db-mysql or the service name you typed in the database creation wizard).
  2. Change your host in the Dokploy Environment Variables UI to match that service name:
    DB_HOST=dokploy-db-mysql  # Use Dokploy's internal container name
    

2. The Config Caching Nightmare (Why changing Env Variables in the UI did nothing)

The Issue

You realized the host was wrong, went to the Dokploy dashboard, updated the DB_HOST environment variable to the correct container hostname, saved, and redeployed.
Yet, the app still threw the old connection error looking for 127.0.0.1. You checked the container logs, confirmed the new environment variables were set, but Laravel simply ignored them.

The Reason

This happens if you run configuration caching in your Dockerfile during the build step:

RUN php artisan config:cache

When Laravel builds your container, it runs config:cache and bakes whatever .env values exist at build-time directly into a static cache file (bootstrap/cache/config.php).
At runtime, Laravel completely ignores your Dokploy UI environment variables and loads the baked-in values instead.

The Solution

Never cache your configuration during the Docker build stage if you plan to change environment variables dynamically.

  1. Remove RUN php artisan config:cache from your build steps.
  2. If you want caching for speed in production, clear it on boot by running php artisan config:clear or php artisan optimize:clear inside your container's startup command / entrypoint script.

3. The Race Condition (Migrations crashing the build)

The Issue

You configured your Docker container to automatically run migrations on deployment:

php artisan migrate --force

But your deployment failed during this step because the database connection timed out or was refused, even though all credentials were 100% correct.

The Reason

When Dokploy restarts or provisions your stack, it starts both the Laravel container and the MySQL/PostgreSQL container simultaneously.
Laravel boots up in milliseconds and immediately tries to run migrations. However, MySQL is still executing its slow initial setup scripts, checking schemas, and opening sockets. The database container isn't ready to receive queries yet, so Laravel's migration command crashes, failing the entire Dokploy deployment.

The Solution

You need to make Laravel "wait" for the database to boot. Add a small bash loop to your entrypoint script (entrypoint.sh) that pings the database port before running migrations:

echo "Waiting for MySQL to boot..."
until nc -z -v -w30 $DB_HOST $DB_PORT; do
  echo "MySQL is not ready yet. Retrying in 2 seconds..."
  sleep 2
done
echo "MySQL is up! Running migrations..."
php artisan migrate --force

4. Port Mapping Confusion (Internal vs. External Ports)

The Issue

Mapping your Dokploy MySQL database port to 3306 (or 3307) externally so you could connect via TablePlus/DBeaver from your laptop, but when configuring your Laravel .env inside Dokploy, you weren't sure which port to use.

The Reason

Docker has two layers of ports:

  • Internal Port: The port the service listens to inside the Docker private network (always 3306 for MySQL).
  • External/Exposed Port: The port mapped to the public server IP so you can connect from the outside world (e.g., mapping host 3307 to container 3306).

Inside Dokploy, your Laravel app and your MySQL container share the same private network. Therefore, they communicate internally.

The Solution

  • For Laravel (.env on Dokploy): Always use the internal port (DB_PORT=3306).
  • For TablePlus/DBeaver (External laptop): Use the exposed host port (3307) and the public server IP.

Summary Checklist for Dokploy deployments

  • Set DB_HOST to the internal Docker container/service name, not 127.0.0.1.
  • Set DB_PORT to the internal port (3306 for MySQL), not the exposed host port.
  • Avoid running php artisan config:cache during Docker build time.
  • Implement a wait-for-it check in your startup script so migrations don't run before MySQL is fully booted.

1 Comment

0 votes
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Mastering Self-Hosted Convex on Dokploy: A Complete Deployment Guide

JoeyOkello - Aug 3

TypeScript Complexity Has Finally Reached the Point of Total Absurdity

Karol Modelskiverified - Apr 23

Delivering Database Changes

Steve Fentonverified - Jul 22

The Audit Trail of Things: Using Hashgraph as a Digital Caliper for Provenance

Ken W. Algerverified - Apr 28

Europe Just Dropped the Hammer on AI: A Wake-Up Call?

PrabashanaDev - Jul 15
chevron_left
151 Points8 Badges
Nairobi
2Posts
0Comments
Fullstack developer || Mobile Developer

Related Jobs

View all jobs →

Commenters (This Week)

3 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!