XAMPP MySQL Shutdown Unexpectedly? My Permanent Fix Using Docker

Author

Kritim Yantra

Sep 07, 2026

XAMPP MySQL Shutdown Unexpectedly? My Permanent Fix Using Docker

XAMPP MySQL Shutdown Unexpectedly? My Permanent Fix Using Docker

You open XAMPP, click Start beside Apache, then start MySQL.

For a second, everything looks fine.

Then MySQL turns red.

Error: MySQL shutdown unexpectedly.

You try again.

Same result.

You restart XAMPP. Run it as administrator. Restart Windows. Change a port. Copy some files. Search Stack Overflow. Maybe it works again for a few days.

Then one morning, the same error comes back.

I got tired of dealing with exactly this problem.

Instead of repeatedly trying to repair XAMPP's MySQL service, I changed my local development setup completely:

I still use XAMPP for Apache and PHP, but I run MySQL separately inside Docker.

And that small change made my local PHP development setup much less frustrating.

My setup now looks like this:

XAMPP
├── Apache
└── PHP

Docker
├── MySQL
├── phpMyAdmin
└── Persistent MySQL Volume

That's it.

No complicated Docker setup.

No need to move the PHP application into Docker.

No need to create a Dockerfile for PHP.

You can continue putting your PHP projects inside:

C:\xampp\htdocs\

and opening them normally through:

http://localhost/my-project

The only difference is that your PHP application connects to MySQL running inside Docker instead of the database server bundled with XAMPP.

In this guide, I'll show you exactly how.


Why Does XAMPP MySQL Keep Shutting Down?

There isn't one single reason behind every "MySQL shutdown unexpectedly" error.

It can happen because of things such as:

  • Another process using the database port
  • Improper shutdowns
  • Corrupted database files
  • Database configuration problems
  • Windows stopping the service incorrectly
  • Conflicts with another MySQL/MariaDB installation
  • Problems after a system crash

There is also something beginners often don't realize.

Although the XAMPP Control Panel displays the service as MySQL, modern XAMPP versions actually ship MariaDB instead of MySQL. Apache Friends says XAMPP switched from MySQL to MariaDB starting with XAMPP 5.5.30 and 5.6.14.

That isn't normally a problem because MySQL and MariaDB are highly compatible for common PHP development.

The problem for me wasn't whether the service was technically MySQL or MariaDB.

The problem was simpler:

I didn't want my database disappearing every time XAMPP decided it didn't want to start.


My Solution: Stop Running MySQL Through XAMPP

Instead of fixing the same XAMPP database problem again and again, I stopped using XAMPP for the database entirely.

I now use:

  • XAMPP Apache for the web server
  • XAMPP PHP for PHP
  • Docker MySQL for the database
  • Docker phpMyAdmin for database management
  • Docker Volume for persistent database storage

Apache Friends officially notes that you can use your own MySQL server with XAMPP; you simply shouldn't start XAMPP's bundled database server at the same time on the same port.

That makes this hybrid setup surprisingly simple.

[Suggested Diagram: XAMPP Apache/PHP connecting from Windows to MySQL running inside Docker, with phpMyAdmin connecting to the same MySQL container.]


Why I Prefer This Setup

The biggest reason is simple:

My database is no longer dependent on XAMPP's MySQL/MariaDB service.

When I open XAMPP, I only care about Apache.

My database has its own container and persistent Docker volume.

There are a few other benefits too.

1. Your Database Has Persistent Storage

Docker containers themselves shouldn't be treated as permanent storage.

That's why we attach a Docker volume to:

/var/lib/mysql

The MySQL files remain in the volume even when the MySQL container stops or is recreated.

Docker's current database documentation recommends this same pattern when running MySQL through Compose.

Think of the container as a rented office and the Docker volume as your filing cabinet.

You can close the office, reopen it, or replace it.

Your files remain in the cabinet.


2. You Can Still Use XAMPP Normally

This is probably my favorite part.

You don't have to Dockerize your entire PHP development environment.

Keep your projects inside:

C:\xampp\htdocs

Keep running Apache using XAMPP.

Keep opening:

http://localhost/project-name

Only your database moves to Docker.

For someone beginning with Docker, this is much easier than putting Apache, PHP, MySQL, Composer, and everything else into containers on day one.


3. You Still Get phpMyAdmin

Moving MySQL into Docker doesn't mean giving up phpMyAdmin.

We'll run phpMyAdmin in another container.

Both containers automatically share a Docker Compose network, allowing phpMyAdmin to reach MySQL using the database service name.

The official phpMyAdmin Docker image supports configuring the database server through PMA_HOST and PMA_PORT.

You'll simply open:

http://localhost:8080

and use phpMyAdmin almost exactly as you did before.


What You Need

Before continuing, install:

  1. XAMPP
  2. Docker Desktop
  3. A text editor such as VS Code

You should also make sure Docker Desktop is running.

That's pretty much everything.


Step 1: Stop MySQL in XAMPP

Open the XAMPP Control Panel.

Start:

Apache

But do not start MySQL.

Your control panel should effectively look like:

Apache     Running
MySQL      Stopped

From now on, XAMPP handles PHP and Apache while Docker handles MySQL.

Important: You generally don't want XAMPP's database server and Docker's MySQL trying to bind to the same Windows port.

Apache Friends specifically warns that two database servers can't start on the same port.


Step 2: Create a Folder for Your Docker Database

Create a folder anywhere you like.

For example:

C:\docker\mysql

Inside it, create:

docker-compose.yml

That's the main file we need.

You don't need a PHP Dockerfile.

You don't need an Apache Dockerfile.

You don't need to rebuild your PHP project.


Step 3: Add This Docker Compose File

Paste the following configuration into docker-compose.yml:

services:
  mysql:
    image: mysql:8.4
    container_name: xampp-mysql
    restart: unless-stopped

    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: my_database
      MYSQL_USER: my_user
      MYSQL_PASSWORD: my_password

    ports:
      - "3307:3306"

    volumes:
      - mysql_data:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: xampp-phpmyadmin
    restart: unless-stopped

    depends_on:
      - mysql

    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306

    ports:
      - "8080:80"

volumes:
  mysql_data:

That's basically the entire setup.

The official MySQL Docker image currently provides the 8.4 tag, while Docker's database documentation demonstrates the same architecture of exposing MySQL on host port 3307, storing /var/lib/mysql in a named volume, and connecting phpMyAdmin to the database container.


Understanding the Docker Compose File

Don't worry if Docker Compose looks strange at first.

Let's break it down.

MySQL Service

mysql:
  image: mysql:8.4

This tells Docker:

Start a container using MySQL 8.4.


MySQL Root Password

MYSQL_ROOT_PASSWORD: root_password

This creates the MySQL root password during the initial database setup.

For local development, replace it with your preferred password.

Warning: Don't use simple credentials like these on a public or production server. This tutorial is intended for local development.


Automatically Create a Database

MYSQL_DATABASE: my_database

MySQL creates this database during the first initialization of an empty data directory.

You could rename it to something related to your project:

MYSQL_DATABASE: ecommerce

or:

MYSQL_DATABASE: krityemiyantra

Create a Normal Database User

MYSQL_USER: my_user
MYSQL_PASSWORD: my_password

Instead of connecting every PHP project using root, we create a normal application user.

That's a better habit.


Why Are We Using Port 3307?

Pay attention to this line:

ports:
  - "3307:3306"

This means:

Windows Port     Docker MySQL Port
3307       --->  3306

MySQL continues listening on its normal port 3306 inside the container.

But Windows accesses it through:

3307

Docker's own MySQL + phpMyAdmin example uses this exact host-to-container port pattern.

Why do I like using 3307?

Because it keeps Docker MySQL clearly separate from any local database service that may already expect 3306.

You could technically use:

"3306:3306"

if nothing else is using 3306.

But using 3307 avoids unnecessary confusion and port conflicts.

Pro Tip: Use 3307 for Docker MySQL and forget about fighting over XAMPP's traditional database port.


The Most Important Part: Docker Volume

Now look at:

volumes:
  - mysql_data:/var/lib/mysql

and:

volumes:
  mysql_data:

This creates a named Docker volume.

Your actual database data lives persistently inside that volume rather than relying only on the container's writable filesystem.

Docker's database guide specifically mounts a named volume at /var/lib/mysql for persistent MySQL data.

This is extremely important.

You can run:

docker compose down

and later:

docker compose up -d

Your databases should still be there because the named volume remains.


Warning: Don't Delete the Volume Unless You Mean It

There is an important difference between:

docker compose down

and:

docker compose down -v

Be careful with:

docker compose down -v

The -v option tells Docker Compose to remove the project's named volumes as well.

That can delete the database storage associated with this Compose setup.

So for normal stopping and starting, use:

docker compose down

or simply:

docker compose stop

Don't casually delete your database volume.


Step 4: Start MySQL and phpMyAdmin

Open PowerShell, Command Prompt, or your terminal inside the folder containing docker-compose.yml.

Run:

docker compose up -d

Docker will download the images if necessary and start both containers.

Check them with:

docker compose ps

You should see your MySQL and phpMyAdmin services running.

You can also use:

docker ps

Step 5: Open phpMyAdmin

Open your browser and visit:

http://localhost:8080

You should see phpMyAdmin.

Login using:

Username: root
Password: root_password

Or use the application user:

Username: my_user
Password: my_password

The phpMyAdmin container connects directly to:

mysql:3306

Why mysql?

Because mysql is the Compose service name:

mysql:

Docker Compose automatically provides networking between services in the same project, and containers can reach one another using the service name. Docker's documentation uses this same approach.


Wait, Why Does phpMyAdmin Use 3306 but PHP Uses 3307?

This confused me initially too, so here's the simple explanation.

phpMyAdmin is inside Docker.

PHP from XAMPP is outside Docker on Windows.

Therefore:

phpMyAdmin container
        |
        | mysql:3306
        v
MySQL container

But your XAMPP PHP application connects like this:

XAMPP PHP
   |
   | 127.0.0.1:3307
   v
Windows
   |
   | port mapping
   v
Docker MySQL:3306

So remember this rule:

Inside Docker:

mysql:3306

From XAMPP PHP:

127.0.0.1:3307

Once you understand that, the entire setup becomes much easier.

[Suggested Diagram: Two connection paths showing phpMyAdmin → mysql:3306 and XAMPP PHP → 127.0.0.1:3307 → MySQL container.]


Step 6: Connect Your XAMPP PHP Project to Docker MySQL

Suppose your PHP project is located here:

C:\xampp\htdocs\my-project

Instead of using:

localhost

with the default MySQL port, connect using:

Host: 127.0.0.1
Port: 3307
Database: my_database
Username: my_user
Password: my_password

PHP MySQLi Connection Example

<?php

$host = '127.0.0.1';
$port = 3307;
$database = 'my_database';
$username = 'my_user';
$password = 'my_password';

$conn = new mysqli(
    $host,
    $username,
    $password,
    $database,
    $port
);

if ($conn->connect_error) {
    die('Database connection failed: ' . $conn->connect_error);
}

echo 'Connected to Docker MySQL successfully!';

Save it as something like:

test-db.php

inside:

C:\xampp\htdocs\my-project\

Then open:

http://localhost/my-project/test-db.php

If everything is configured correctly, you'll see:

Connected to Docker MySQL successfully!

That PHP file is still being executed by XAMPP PHP.

The database connection simply goes to Docker.


PDO Connection Example

If you prefer PDO:

<?php

$host = '127.0.0.1';
$port = 3307;
$database = 'my_database';
$username = 'my_user';
$password = 'my_password';

$dsn = "mysql:host={$host};port={$port};dbname={$database};charset=utf8mb4";

try {
    $pdo = new PDO($dsn, $username, $password, [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]);

    echo 'Connected to Docker MySQL successfully!';
} catch (PDOException $e) {
    die('Database connection failed: ' . $e->getMessage());
}

The important values are still:

127.0.0.1
3307
my_database
my_user
my_password

Using the Same Database in PHP and phpMyAdmin

This is another reason I like this setup.

There aren't two databases.

phpMyAdmin and your PHP application are accessing the same MySQL server and the same Docker volume.

For example, create a table using phpMyAdmin:

CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(150) NOT NULL
);

Then insert something from PHP.

Refresh phpMyAdmin.

The new data appears there.

That's because both applications are talking to the same MySQL container.


What If I Already Have a Database in XAMPP?

You probably don't want to lose an existing PHP project's database.

Before switching, export it.

Step 1: Start Your Old XAMPP Database One Last Time

If it still starts, open the old XAMPP phpMyAdmin.

Usually:

http://localhost/phpmyadmin

Select your database.

Choose:

Export → Quick → SQL → Export

Save the .sql file.


Step 2: Start Docker MySQL

Stop XAMPP MySQL and start your Docker environment:

docker compose up -d

Step 3: Open Docker phpMyAdmin

Visit:

http://localhost:8080

Select or create your database.

Choose:

Import

Upload your .sql file.

Now your old PHP project can use the migrated database through:

127.0.0.1:3307

Pro Tip: Always keep a separate database backup before migrating or experimenting with database storage.


Your Daily Development Workflow Becomes Very Simple

After setting this up once, my normal workflow becomes:

Start XAMPP Apache

Open XAMPP and start only:

Apache

Don't start MySQL.


Start Docker Database

From the folder containing your Compose file:

docker compose up -d

That's it.

Now you have:

PHP Website:
http://localhost/my-project

phpMyAdmin:
http://localhost:8080

MySQL:
127.0.0.1:3307

When You're Finished Working

You have two choices.

You can leave the containers running.

Or stop them:

docker compose stop

Start them again later:

docker compose start

You can also use:

docker compose down

and recreate them later:

docker compose up -d

Because the database files live in the named volume, recreating the container doesn't mean starting from an empty database.


Useful Docker Commands for This Setup

You really don't need many Docker commands.

Start Everything

docker compose up -d

Check Status

docker compose ps

Stop Containers

docker compose stop

Start Existing Containers

docker compose start

Remove Containers Without Intentionally Removing the Named Volume

docker compose down

View MySQL Logs

docker compose logs mysql

The official MySQL image documentation also recommends Docker logs as a way to inspect the MySQL server's output.

If something isn't starting correctly, this command is much more useful than randomly changing files:

docker compose logs mysql

Do I Still Need XAMPP phpMyAdmin?

No.

That's another nice part of this setup.

You can ignore XAMPP's built-in phpMyAdmin and use:

http://localhost:8080

The Docker phpMyAdmin container connects directly to Docker MySQL.

The official phpMyAdmin Docker image supports this configuration through:

PMA_HOST: mysql
PMA_PORT: 3306

Why Not Put PHP in Docker Too?

You absolutely can.

A fully containerized setup might include:

Nginx/Apache
PHP
MySQL
phpMyAdmin
Redis

inside Docker.

For larger projects, teams, or environments where consistency is critical, that can be a great setup.

But that isn't what I'm trying to solve here.

I wanted something simple.

I already liked using XAMPP for PHP development.

My frustration was the database shutdown problem.

So rather than rebuilding everything, I replaced only the part causing trouble.

Sometimes the simplest solution is the one you'll actually continue using.


Common Mistakes to Avoid

1. Starting XAMPP MySQL Anyway

Once you're using Docker MySQL, you generally don't need to start XAMPP's database service.

Your workflow becomes:

XAMPP:
Apache = ON
MySQL = OFF

Docker:
MySQL = ON
phpMyAdmin = ON

Keep it simple.


2. Using Port 3306 in Your XAMPP PHP Configuration

Remember that the Compose file exposes MySQL on Windows through:

3307

So this may fail:

$port = 3306;

Use:

$port = 3307;

for PHP running directly through XAMPP.


3. Using mysql as the Host in XAMPP PHP

This:

$host = 'mysql';

works for another container on the same Docker Compose network.

Your XAMPP PHP installation isn't inside that network.

Use:

$host = '127.0.0.1';

4. Using 127.0.0.1:3307 for Docker phpMyAdmin

phpMyAdmin is already inside Docker.

It should connect directly to:

mysql:3306

That's why our Compose file contains:

PMA_HOST: mysql
PMA_PORT: 3306

5. Running docker compose down -v Without Knowing What It Does

This deserves repeating.

Don't casually run:

docker compose down -v

when your database is important.

The volume is where your MySQL data persists.

Keep backups of anything you can't afford to lose.


6. Changing MYSQL_DATABASE and Expecting an Existing Volume to Reset

This catches beginners surprisingly often.

Environment variables such as:

MYSQL_DATABASE
MYSQL_USER
MYSQL_PASSWORD

are primarily used when MySQL initializes an empty data directory.

The official MySQL Docker image documentation notes that initialization variables don't reinitialize a database directory that already contains a database.

So if your volume already contains MySQL data, simply changing:

MYSQL_DATABASE: new_database

doesn't mean Docker will wipe everything and recreate the server.

And that's a good thing.


Is This Really a Permanent Fix for XAMPP MySQL Shutdown?

Here's how I think about it.

This doesn't magically repair every possible cause of XAMPP's "MySQL shutdown unexpectedly" error.

Instead, it removes that database service from my development workflow.

I no longer depend on XAMPP's bundled database server.

So for me, that recurring XAMPP MySQL shutdown problem effectively stopped mattering.

Could Docker MySQL itself have a problem one day?

Of course.

No software is guaranteed never to fail.

But the database is now isolated, reproducible through one Compose file, easier to inspect through container logs, and stored in a persistent Docker volume.

That's a much cleaner workflow for me.


The Entire Setup in One File

This is the part I really like.

Your database development environment can basically be represented by this single file:

services:
  mysql:
    image: mysql:8.4
    container_name: xampp-mysql
    restart: unless-stopped

    environment:
      MYSQL_ROOT_PASSWORD: root_password
      MYSQL_DATABASE: my_database
      MYSQL_USER: my_user
      MYSQL_PASSWORD: my_password

    ports:
      - "3307:3306"

    volumes:
      - mysql_data:/var/lib/mysql

  phpmyadmin:
    image: phpmyadmin:latest
    container_name: xampp-phpmyadmin
    restart: unless-stopped

    depends_on:
      - mysql

    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306

    ports:
      - "8080:80"

volumes:
  mysql_data:

Then:

docker compose up -d

And you're ready.

Your PHP remains inside XAMPP.

Your database runs through Docker.

Your database files persist in a Docker volume.

phpMyAdmin runs at port 8080.

Your PHP application connects through port 3307.

Simple.


Final Thoughts

If you've searched for the XAMPP MySQL shutdown unexpectedly error multiple times, you probably understand the frustration.

You fix it.

It works.

Then eventually you're looking at the same red error message again.

That was the point where I decided I didn't want to keep fixing the same part of my development environment.

I still use XAMPP because it makes running Apache and PHP incredibly convenient.

I simply stopped asking XAMPP to manage my database.

Now my setup is:

XAMPP = Apache + PHP

Docker = MySQL + phpMyAdmin + Database Volume

For local PHP development, I've found this combination simple, understandable, and much less frustrating.

If you're currently fighting with the XAMPP MySQL shutdown error, back up your existing database and try moving only MySQL to Docker.

You don't need to Dockerize your entire application.

Start with the part that's causing you problems.

Have you also experienced XAMPP's "MySQL shutdown unexpectedly" error? What solution have you been using to deal with it?


FAQ

How do I permanently fix XAMPP MySQL shutdown unexpectedly?

There isn't one fix for every cause of the error. One reliable alternative is to stop using XAMPP's bundled database service and run MySQL separately in Docker while continuing to use XAMPP for Apache and PHP.

Your XAMPP PHP application can then connect to Docker MySQL through 127.0.0.1:3307.


Can I use Docker MySQL with XAMPP PHP?

Yes.

Your PHP application can continue running normally through XAMPP while connecting to a MySQL container exposed on your Windows machine.

For the configuration used in this tutorial:

Host: 127.0.0.1
Port: 3307

Apache Friends also confirms that XAMPP can be used with your own database server as long as you avoid database services competing for the same port.


Will my Docker MySQL database disappear when I stop Docker?

Not if you configure persistent storage correctly.

This tutorial attaches a named Docker volume:

mysql_data:/var/lib/mysql

That volume stores the MySQL database files independently from the normal lifecycle of the container.

Still, keep proper backups of important databases.


Can I use phpMyAdmin with MySQL running in Docker?

Yes.

The official phpMyAdmin Docker image can connect to another database container by setting variables such as:

PMA_HOST: mysql
PMA_PORT: 3306

In this setup, you access it through:

http://localhost:8080

Why does PHP use port 3307 while phpMyAdmin uses 3306?

Your XAMPP PHP application runs on Windows outside Docker, so it accesses the exposed host port:

127.0.0.1:3307

phpMyAdmin runs inside the same Docker Compose network as MySQL, so it connects directly to:

mysql:3306

Do I need to Dockerize PHP too?

No.

That's the whole idea behind this setup.

You can continue using XAMPP for:

Apache + PHP

and use Docker only for:

MySQL + phpMyAdmin

It's a good way to start using Docker without completely changing your existing PHP workflow.

Comments

No comments yet. Be the first to comment!

Please log in to post a comment:

Sign in with Google

Related Posts

Advanced Docker Interview Questions and Answers (2025)

Web Development

Running PHP 8.4 in Docker with Local File Mounting

Web Development

Building a PHP 8.4 + MySQL Docker Development Environment: Complete Guide

Web Development