Fix “MySQL shutdown unexpectedly” in XAMPP —
and stop it coming back
Updated · Windows 10 and 11
The short answer
This error almost never means your data is gone. It means InnoDB was killed mid-write, its redo log no longer matches its data files, and it is refusing to start rather than risk making things worse.
To recover now: stop XAMPP, rename
xampp\mysql\data to
data_old, copy
xampp\mysql\backup to a new
data folder, then copy your own
database folders and
ibdata1 from
data_old into it.
Full steps below.
To stop it happening again: run MySQL as a Windows service, not as a
process XAMPP kills. Why that works.
What the error actually is
The message XAMPP shows you is not MySQL's message. It is XAMPP's summary of what it observed: it launched
mysqld.exe, the process exited on its own, and XAMPP does not
know why. The full text is usually some version of this:
Error: MySQL shutdown unexpectedly.
This may be due to a blocked port, missing dependencies,
improper privileges, a crash, or a shutdown by another method.
That list is XAMPP guessing. The real reason is written down in a file XAMPP does not show you:
xampp\mysql\data\mysql_error.log. Open it and read the last
twenty lines before you touch anything. If you see phrases like
InnoDB: Database page corruption,
Log scan progressed past the checkpoint lsn, or
Plugin 'InnoDB' init function returned error, you have the
corruption case this page is about.
If instead you see Can't start server: Bind on TCP/IP port,
you have a completely different and much easier problem: something else is already on port 3306. That is
usually a MySQL service left behind by a previous install, or Windows' own MySQL Installer. Stop that service
and start XAMPP again.
Why InnoDB ends up in this state
InnoDB does not write your changes straight into the table files. When you insert a row, it writes the change
into an in-memory buffer pool and appends a record to a redo log
(ib_logfile0). The actual data file
(ibdata1 and the
.ibd files) gets updated later, in batches, because writing
every change immediately would be brutally slow.
That design is safe as long as MySQL gets to finish. On a clean shutdown it flushes the buffer pool to disk, writes a checkpoint saying “everything up to this point is on disk,” and exits. On the next start it sees the checkpoint, sees a matching log, and starts in a second.
Now consider what XAMPP does instead. Its control panel starts
mysqld.exe as an ordinary child process, and when you press
Stop — or close the panel, or log off, or Windows restarts for an update — it terminates that
process. Not a request to shut down. A kill.
So InnoDB dies with a buffer pool full of changes that were never written and a redo log full of records past the last checkpoint. On the next start it tries crash recovery: replay the log forward from the checkpoint. When that replay hits something inconsistent — a page half-written because the kill landed in the middle of a disk write — it stops. It will not guess. It logs the problem and exits, and XAMPP tells you MySQL shut down unexpectedly.
This is why the error feels random and why it keeps coming back. It is not caused by anything you did wrong in your code or your database. It is caused by how the process was stopped, and under XAMPP that is the same every single time.
Recover your databases
These steps rebuild a working system database from the pristine copy XAMPP ships in
xampp\mysql\backup, then put your own data back into it. Work
through them in order and do not skip step 5.
-
Stop XAMPP completely. Close the XAMPP Control Panel. Open Task Manager,
go to the Details tab, and end any
mysqld.exestill running. If a MySQL process is holding a file lock, every step below will silently half-fail. -
Rename the broken folder. Go to your XAMPP folder, open
mysql, and renamedatatodata_old. Do not delete it. It holds the only copy of your databases that exists. -
Rebuild a clean one. Copy the whole
backupfolder (still insidexampp\mysql) and rename the copy todata. You now have an untouched system database MySQL can definitely start against. -
Put your databases back. Open
data_old. Every folder in there is one database. Copy the ones that are yours into the newdatafolder. Leave behindmysql,performance_schema,phpmyadmin, andtest— the clean versions came from the backup. -
Copy
ibdata1. Takeibdata1fromdata_oldand drop it into the newdatafolder, overwriting the one already there. This is the step people miss. The folders you copied in step 4 are mostly table definitions; the rows themselves live inibdata1. Skip it and your tables come back empty. -
Do not copy
ib_logfile0orib_logfile1. Those are the corrupted redo logs that caused this. Leaving them out lets MySQL create fresh ones. - Start MySQL. Open the XAMPP Control Panel and start it. Then open phpMyAdmin and check not just that your databases are listed, but that a table you know has rows in it still does.
If that did not work
Fall back to innodb_force_recovery. Open
xampp\mysql\bin\my.ini, find the
[mysqld] section, and add this line:
innodb_force_recovery=1
Start MySQL. If it comes up, treat it as a rescue window, not a fix: export everything immediately with
phpMyAdmin's Export tab or mysqldump, then remove the line and
rebuild the data folder from scratch. If it still will not start, raise the number one step at a time. Levels
1 to 3 are generally safe. Levels 4 to 6 can permanently discard data to force a start, so only go there when
the alternative is losing everything anyway — and export the moment you get in.
Stopping it permanently
Everything above repairs the damage. None of it touches the cause. If MySQL is still being hard-killed every time you close XAMPP, you have bought yourself some time, not a solution — and most people doing this dance are doing it for the third or fourth time.
The fix is to change how MySQL is stopped. Windows already has the right mechanism: the Service Control
Manager. When a program is registered as a Windows service, shutting it down sends it a
SERVICE_CONTROL_STOP control code rather than terminating it.
MySQL handles that code as a graceful shutdown — flush the buffer pool, write the checkpoint, close the
tablespace, exit. And critically, Windows sends it automatically on log-off, restart, and update reboots, so
the crash-on-shutdown path disappears even when you are not the one closing anything.
This is the difference visible in the logs. Under a service, a shutdown looks like this:
[Note] Windows service "HelmMySQL": received SERVICE_CONTROL_STOP
[Note] mysqld.exe (initiated by: unknown): Normal shutdown
[Note] InnoDB: Starting shutdown...
[Note] InnoDB: Dumping buffer pool(s) to ib_buffer_pool
[Note] Shutdown completed; log sequence number 44776
[Note] mysqld.exe: Shutdown complete
Nothing to recover on the next start, because nothing was left unfinished.
Two ways to get there
Register XAMPP's MySQL as a service yourself. The XAMPP Control Panel has a
checkbox in the left column of each row that installs the service, and it does help. Be aware of the
trade-offs: the checkbox requires running the panel as administrator, it does not survive a XAMPP upgrade,
recent MariaDB builds removed the mysqld --install flag that
some XAMPP versions still rely on, and Apache and MySQL each need doing separately. It is a real fix, but a
manual one you have to maintain.
Or use something that does it by default. That is what we built Helm for, after losing the same database one time too many.
The permanent fix
Helm is a free, single-installer replacement for XAMPP on Windows. Apache, PHP, MySQL (MariaDB), and
phpMyAdmin all come in one .exe, it
installs to C:\Helm, and it registers
Apache and MySQL as real Windows services during setup — so MySQL is shut down properly, every time,
without you having to think about it.
- One installer. No separate downloads, no Visual C++ prerequisite hunt.
- Clean
SERVICE_CONTROL_STOPshutdowns by default. - Reads
mysql_error.logand tells you in plain English what went wrong, instead of listing five possible causes. - One-click database backup, so the next scare is a restore rather than a rescue.
- phpMyAdmin with no login round-trip, and per-project
.localdomains. - Free, MIT licensed, and the source is on GitHub.
Windows 10/11 · 64-bit · Free · MIT licensed
Moving your databases across
If you switch, do it with the databases intact rather than starting over. Recover XAMPP one last time using
the steps above, open phpMyAdmin, select each database, and use the Export tab with the default Quick / SQL
settings. Install Helm, open its phpMyAdmin at
http://localhost/phpmyadmin, create the database, and import
the .sql file. Your project files move by copying them into
Helm's htdocs folder, which works the same way XAMPP's does.
Common questions
Will I lose my data?
Usually not. MySQL is refusing to start, which is a different thing from your data being gone. The rule that
matters: rename the data folder, never delete it. Everything
recoverable is in there.
Why does it keep happening to the same project?
It is not the project. It is whichever database had unflushed changes in the buffer pool at the moment of the kill, which is naturally the one you were just working in.
Does reinstalling XAMPP fix it?
It clears the current corruption and loses your databases along the way, and it changes nothing about how MySQL gets stopped. The error returns.
Is this a MySQL bug?
No. InnoDB refusing to start on an inconsistent log is it working correctly — the alternative is silently serving you corrupted rows. The problem is upstream, in how the process is being terminated.
I am on macOS or Linux — same thing?
The InnoDB mechanics are identical, but the trigger is rarer, because MAMP and most Linux setups stop MySQL with a signal it can handle rather than an outright kill. This particular crash loop is largely a Windows and XAMPP problem. Helm is Windows-only for the same reason.