When Database Tables Disappear After a Power Outage

Estimated read time 17 min read

A power outage, forced restart, or storage interruption is a documented real-world trigger for MariaDB/XAMPP corruption. Plesk’s article “How to fix InnoDB corruption cases for the MySQL/MariaDB databases on Plesk for Windows” identifies power failures as one cause of corrupted page writes, while noting that bad memory and some storage configurations can produce similar damage (Plesk, 2025). The visible symptom may look simple at first: XAMPP says MySQL shut down unexpectedly, or MariaDB starts but individual tables fail. Then one query exposes the serious error: MariaDB says the table does not exist in the storage engine.

That pattern is consistent with documented InnoDB failure modes. The DigitalOcean Community tutorial “How to fix corrupted tables in MySQL” discusses practical corruption-recovery steps, MariaDB’s “InnoDB Recovery Modes” page explains that emergency recovery is meant to make data readable enough to dump, and Plesk’s Windows InnoDB corruption article recommends creating database dumps during forced recovery (DigitalOcean, 2022; MariaDB Foundation, n.d.-a; Plesk, 2025). Together, those sources support the central idea of this guide: use recovery mode or tablespace recovery only as a bridge to verified SQL dumps, not as the final state.

This guide walks through a practical recovery workflow for the case where old InnoDB table files survive on disk. It is written for developers, sysadmins, hosting operators, and technical founders who need a disciplined path from first failure to verified recovery.

The companion GitHub recovery kit contains the generalized scripts and checklists used by this guide.

GitHub repository: https://github.com/aspectsoftgr/innodb-rescue-kit

Start With a Safe Working Copy

The first rule is preservation. If MariaDB has lost track of an InnoDB table, the remaining .frm, .ibd, ibdata, and log files may be the only usable source for recovery. MariaDB’s InnoDB recovery documentation explicitly warns to make a backup before emergency recovery changes, so every attempt should be reversible (MariaDB Foundation, n.d.-a).

Work on copies. Preserve the original data directory, then create a clean MariaDB data folder for recovery attempts. The old folder should be treated as a source of evidence, not as the final database.

  • Stop MariaDB before moving or copying data folders.
  • Keep the original data directory read-only or copied to another drive where practical.
  • Do not delete ibdata1, ib_logfile*, .frm, .ibd, .MAD, or .MAI files during triage.
  • Do not assume that a table listed in phpMyAdmin is readable until SELECT, CHECK TABLE, and mysqldump prove it.

What the Error Usually Means

The central symptom in this recovery pattern is not just that MySQL or MariaDB “shut down unexpectedly.” The important symptom is a table-level error like this:

ERROR 1932 (42S02): Table ‘database.table’ doesn’t exist in engine

That message often appears when table files still exist on disk, but InnoDB’s internal dictionary no longer recognizes the table. A sudden power loss is not the only cause, but it is a credible trigger because interrupted writes can leave database pages, system tables, or tablespace metadata inconsistent. MariaDB’s “InnoDB file-per-table tablespaces” page describes separate .ibd files, Oracle’s “Importing InnoDB tables” page documents DISCARD TABLESPACE / IMPORT TABLESPACE workflows, and Plesk’s Windows InnoDB corruption article documents page-write corruption as a practical failure mode (MariaDB Foundation, n.d.-b; Oracle, n.d.-a; Plesk, 2025).

The recovery model in this guide is therefore: recover the table definition, recreate the table in a clean server, import the old tablespace, dump the data to SQL, verify the dump, and rebuild a clean final server from verified SQL.

Stage 1: Start MariaDB Enough to Inspect the Damage

XAMPP’s control panel often shows only a short failure message. Start MariaDB directly from the console to see the real error.

cd /d C:\xampp\mysql\bin

mysqld --defaults-file="C:\xampp\mysql\bin\my.ini" --console

If the console reports a corrupted system privilege table, such as mysql.db, restore only the damaged system table files from a known-good XAMPP backup after making copies of the broken files. This is not the final recovery; it is only a way to get the server far enough to inspect and dump what is still readable. For InnoDB corruption, MariaDB’s guidance favors emergency recovery and dump/reload patterns over relying on REPAIR TABLE-style fixes (MariaDB Foundation, n.d.-a).

copy /Y C:\xampp\mysql\data\mysql\db.frm C:\xampp\mysql\data\mysql\db.frm.broken

copy /Y C:\xampp\mysql\data\mysql\db.MAD C:\xampp\mysql\data\mysql\db.MAD.broken

copy /Y C:\xampp\mysql\data\mysql\db.MAI C:\xampp\mysql\data\mysql\db.MAI.broken

copy /Y C:\xampp\mysql\backup\mysql\db.frm C:\xampp\mysql\data\mysql\db.frm

copy /Y C:\xampp\mysql\backup\mysql\db.MAD C:\xampp\mysql\data\mysql\db.MAD

copy /Y C:\xampp\mysql\backup\mysql\db.MAI C:\xampp\mysql\data\mysql\db.MAI

Once MariaDB starts, immediately identify which databases and tables are readable, which are broken, and which healthy databases need a normal dump before any deeper recovery work begins.

Stage 2: Preserve the Old Data Directory

Before attempting .ibd recovery, separate the old source files from the clean recovery target. A typical local XAMPP layout looks like this:

C:\xampp\mysql\data                         active clean recovery target

C:\xampp\mysql\data_orphaned_for_recovery   old source files

Stop MariaDB first, then rename or copy the existing data folder. If you have an earlier clean XAMPP data folder available, use it as the active recovery target. Otherwise create one from the XAMPP backup template.

taskkill /F /IM mysqld.exe

cd /d C:\xampp\mysql

ren data data_orphaned_for_recovery

mkdir data

xcopy C:\xampp\mysql\backup C:\xampp\mysql\data /E /I /H /K /Y

From this point on, the old folder is the source. The clean data folder is where recovery attempts happen.

Stage 3: Identify the Broken Table Queue

Use mysqlcheck or targeted SQL probes to find tables that fail with “doesn’t exist in engine.” The result should be a plain text queue in database.table format.

cd /d C:\xampp\mysql\bin

mysqlcheck -u root -proot --all-databases > C:\mariadb_check_all.txt

Then extract the broken table names in PowerShell:

Select-String -Path C:\mariadb_check_all.txt -Pattern "Table '([^']+)' doesn't exist in engine" |

  ForEach-Object { $_.Matches[0].Groups[1].Value } |

  Sort-Object -Unique |

  Set-Content C:\broken_tables_exact.txt

The queue should look like this:

exampledb.users

exampledb.orders

shopdb.products

cmsdb.posts

For each queued table, confirm that the old source folder contains both a .frm and a .ibd file. Without those files, this particular recovery path cannot proceed.

Stage 4: Prove Recovery on One Table

Do not begin with hundreds of tables. Pick one important table and prove the method. The usual process is to extract the schema from the .frm file, recreate the table in clean MariaDB, discard the generated tablespace, copy the old .ibd file, and import it. This follows the same general transportable-tablespace sequence documented by MySQL and MariaDB, adapted for a recovery scenario where the old server cannot cleanly export a .cfg file (MariaDB Foundation, n.d.-b; Oracle, n.d.-a).

The dbsake frmdump command can decode a MySQL .frm file and output a CREATE TABLE or CREATE VIEW statement without requiring a running MySQL server (dbsake, n.d.).

C:\Python3\python.exe C:\tools\dbsake frmdump ^

  C:\xampp\mysql\data_orphaned_for_recovery\exampledb\users.frm ^

  > C:\users_schema.sql

If the import later fails with a missing .cfg message, remove secondary indexes from the CREATE TABLE statement. Keep the primary key, but remove ordinary KEY, UNIQUE KEY, FULLTEXT KEY, SPATIAL KEY, CONSTRAINT, and FOREIGN KEY lines for the import attempt.

CREATE DATABASE IF NOT EXISTS `exampledb`;

USE `exampledb`;

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (

  `id` int(11) NOT NULL AUTO_INCREMENT,

  `email` varchar(255) NOT NULL,

  PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

ALTER TABLE `users` DISCARD TABLESPACE;

After DISCARD TABLESPACE, stop MariaDB, copy the old .ibd file into the clean database folder, start MariaDB again, and import the tablespace.

taskkill /F /IM mysqld.exe

copy /Y C:\xampp\mysql\data_orphaned_for_recovery\exampledb\users.ibd ^

  C:\xampp\mysql\data\exampledb\users.ibd

cd /d C:\xampp\mysql\bin

mysql -u root -proot -e "ALTER TABLE exampledb.users IMPORT TABLESPACE;"

A successful import is not enough. Check, count, and dump the table immediately.

mysql -u root -proot -e "CHECK TABLE exampledb.users;"

mysql -u root -proot -e "SELECT COUNT(*) FROM exampledb.users;"

mysqldump -u root -proot exampledb users --single-transaction --quick --result-file="C:\recovered_exampledb.users.sql"

Why Secondary Indexes Become a Problem

Transportable tablespace import expects metadata that is normally produced when a table is exported cleanly. The MariaDB documentation describes copying both .ibd and .cfg files after DISCARD TABLESPACE / export-style workflows, and MySQL documents transportable tablespaces as the formal method for importing file-per-table tablespaces (MariaDB Foundation, n.d.-b; Oracle, n.d.-a). In crash recovery, the .cfg file is often missing. MariaDB or MySQL may then reject the import and tell you to drop all secondary indexes first.

That instruction sounds strange, but it is useful. The row data is stored in the clustered primary key when one exists. Secondary indexes can be rebuilt later from SQL. For recovery, the priority is to get the rows readable and dumped.

Stage 5: Bulk-Recover the Queue

After the one-table proof works, automation becomes safer. The GitHub kit provides a bulk PowerShell script that processes a database.table queue, extracts schemas, patches common problems, imports .ibd files, checks tables, counts rows, and dumps each recovered table.

$env:PYTHONIOENCODING = "utf-8"

$env:PYTHONUTF8 = "1"

Set-ExecutionPolicy -Scope Process Bypass

C:\recover_orphaned_tables.ps1

The recovery log should classify each table with a status such as OK, ALREADY_OK, FAIL, or SKIP. Failures should not stop the run. They should be grouped and handled by type.

Import-Csv C:\ibd_recovery_log.csv |

  Group-Object Status |

  Select-Object Name, Count

Stage 6: Handle the Real-World Edge Cases

The clean recovery path is simple. The real work starts when different tables fail for different reasons. The most common categories are schema extraction failures, invalid defaults, import failures, and CHECK TABLE warnings.

Invalid timestamp or datetime defaults are common in older schemas. A generated definition such as this may fail:

`last_login` timestamp DEFAULT NULL

Patch it to make NULL explicit:

`last_login` timestamp NULL DEFAULT NULL

dbsake may also crash while decoding BLOB or LONG_BLOB defaults. The GitHub kit includes a small Python wrapper that patches dbsake at runtime so BLOB defaults do not stop schema extraction. This workaround is narrowly scoped: dbsake’s own documentation notes that frmdump decodes information available in the .frm file, so the goal is schema reconstruction, not data recovery from the .frm itself (dbsake, n.d.).

C:\Python3\python.exe C:\tools\dbsake_blobfix_runner.py frmdump ^

  C:\xampp\mysql\data_orphaned_for_recovery\exampledb\products.frm ^

  > C:\products_schema.sql

On Windows, Python may fail when writing schema output with non-CP1252 characters. Force UTF-8 for those runs:

$env:PYTHONIOENCODING = "utf-8"

$env:PYTHONUTF8 = "1"

A decoded default can also be invalid because the value is longer than the declared varchar width. In recovery, defaults are not the data you are trying to save. Patch the default to a safe value and continue.

Stage 7: Salvage Tables That Import but Fail CHECK TABLE

Some tables import but CHECK TABLE reports a corrupted B-tree. That table should not be trusted as a live final table. But if SELECT works, it may still be possible to dump the rows to SQL. This follows the same practical direction as InnoDB recovery guidance: get the server readable enough to dump and reload rather than treating the damaged table as the final state (DigitalOcean, 2022; MariaDB Foundation, n.d.-a).

mysql -u root -proot -e "SELECT COUNT(*) FROM exampledb.problem_table;"

mysqldump -u root -proot exampledb problem_table --skip-lock-tables --quick --result-file="C:\salvage\exampledb.problem_table.sql"

The SQL dump is then verified like every other dump. If it imports cleanly into a fresh verification database and the row count matches, it becomes the trusted artifact. The imported .ibd table remains only a recovery bridge.

Stage 8: Verify Every Recovered Dump

This is the step that separates a lucky recovery from a trustworthy one. Do not rely only on the fact that a table could be queried once. Re-import every dump into fresh verification databases and compare row counts. Logical dumps are designed for backup or transfer between database servers, making them the right artifact to verify and preserve (MariaDB Foundation, n.d.-c).

C:\verify_recovered_dumps.ps1

Import-Csv C:\dump_import_verify_log.csv |

  Group-Object ImportStatus, CountStatus |

  Select-Object Name, Count

The best result is that every dump imports successfully and every row count matches. Then run mysqlcheck on the verification databases.

$verifyDbs = & C:\xampp\mysql\bin\mysql.exe -u root -proot -N -e "SHOW DATABASES LIKE 'verify_%';"

$results = foreach ($db in $verifyDbs) {

  & C:\xampp\mysql\bin\mysqlcheck.exe -u root -proot --databases $db

}

$results | Out-File C:\verify_mysqlcheck.txt

Select-String -Path C:\verify_mysqlcheck.txt -Pattern "error|corrupt|warning|failed|doesn't exist" -CaseSensitive:$false

If the final Select-String command prints nothing, the verification databases passed this first practical integrity check.

Stage 9: Export Users and Grants

Database files are not the only state that matters. Application accounts, root access, phpMyAdmin users, and service users may be stored in MariaDB’s privilege tables. Export users and grants before rebuilding the final clean server.

C:\export_mariadb_users_grants.ps1

Use SHOW GRANTS rather than copying mysql system tables into the final server. Also avoid using a PowerShell variable named $host, because $Host is a built-in read-only variable and PowerShell variable names are case-insensitive.

Stage 10: Rebuild the Final Clean Data Folder

The recovery workspace should not be the long-term database. Once the SQL dumps are verified, build a fresh clean MariaDB data folder and import the verified dumps into it.

taskkill /F /IM mysqld.exe

cd /d C:\xampp\mysql

ren data data_recovery_workspace_final

mkdir data

xcopy C:\xampp\mysql\backup C:\xampp\mysql\data /E /I /H /K /Y

Start MariaDB, set or confirm the root password, then import the verified dumps. When a normal dump and a salvage dump exist for the same table, prefer the salvage dump if that is the one that verified cleanly.

C:\final_clean_import.ps1

cd /d C:\xampp\mysql\bin

mysql -u root -proot < C:\mariadb_users_grants.sql

Verify final row counts against the earlier verification log:

C:\final_rowcount_verify.ps1

Import-Csv C:\final_clean_rowcount_verify.csv |

  Group-Object Status |

  Select-Object Name, Count

Stage 11: Check for Healthy Databases That Were Never in the Queue

A subtle problem can appear after a clean rebuild. Broken-table recovery only imports tables that were in the broken-table queue. A database that was healthy earlier may not appear in that queue, especially if it was dumped separately or contained no broken tables.

Compare old database folder names with the current server:

C:\compare_old_and_current_databases.ps1

If a missing database folder contains only db.opt, it was probably an empty database. Preserve the name if the application expects it:

mysql -u root -proot -e "CREATE DATABASE IF NOT EXISTS missing_database DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

If the folder contains .frm and .ibd files, add those tables to a temporary queue and run the recovery process for that database.

After the final clean import and row-count verification, run mysqlcheck across the clean server and search for warning or error patterns. This does not prove every application-level invariant, but it is a useful final database-integrity screen before the full backup.

cd /d C:\xampp\mysql\bin

mysqlcheck -u root -proot --all-databases > C:\final_clean_mysqlcheck.txt

Select-String -Path C:\final_clean_mysqlcheck.txt -Pattern "error|corrupt|warning|failed|doesn't exist" -CaseSensitive:$false

If that search prints nothing, create the final full SQL backup:

mysqldump -u root -proot ^

  --all-databases ^

  --routines ^

  --events ^

  --triggers ^

  --single-transaction ^

  --quick ^

  --result-file="C:\final_clean_all_databases.sql"

What to Keep

Keep the verified SQL artifacts and logs. They explain what was recovered and make the recovery reproducible.

  • The final full SQL dump of the clean server.
  • The users/grants export.
  • The per-table recovered dumps and salvage dumps.
  • The dump verification log and final row-count verification log.
  • The final mysqlcheck output.
  • The old source data folder, at least until external backups are confirmed and the applications have run normally for a while.

Field Checklist

  • Preserve the original data directory before doing anything else.
  • Start MariaDB from the console to see the real startup error.
  • Repair system tables only enough to inspect and dump data.
  • Build a database.table queue of broken tables.
  • Prove the method on one table before bulk recovery.
  • Remove secondary indexes when .cfg metadata is missing.
  • Patch invalid defaults in generated schemas when needed.
  • Use the dbsake BLOB workaround if schema extraction fails on BLOB defaults.
  • Force UTF-8 output on Windows if schema extraction hits Unicode errors.
  • Dump every recovered table to SQL immediately.
  • For CHECK-failed tables, try SELECT and mysqldump salvage.
  • Verify every dump by importing it into a fresh verification database.
  • Rebuild the final server from verified SQL, not from copied .ibd files.
  • Export and restore MariaDB users/grants separately.
  • Check for healthy databases that were not in the broken-table queue.
  • Run final mysqlcheck and create a final full backup.

Prevention

The best recovery is the one you never need. Local development databases and small production servers both need scheduled logical backups. MariaDB’s dump documentation describes mariadb-dump as a tool for backing up or transferring databases, which is exactly the portable artifact this recovery process tries to reconstruct after the fact (MariaDB Foundation, n.d.-c).

cd /d C:\xampp\mysql\bin

mysqldump -u root -proot ^

  --all-databases ^

  --routines ^

  --events ^

  --triggers ^

  --single-transaction ^

  --quick ^

  --result-file="D:\mariadb_backups\all_databases.sql"

For machines exposed to sudden power loss, use a UPS and durability-oriented settings. Adapt these to your workload and test them before using them on production systems. MySQL’s own documentation recommends innodb_flush_log_at_trx_commit=1 and sync_binlog=1 for durability and consistency in transactional setups that use binary logging (Oracle, n.d.-b).

[mysqld]

default_storage_engine=InnoDB

innodb_flush_log_at_trx_commit=1

innodb_doublewrite=1

sync_binlog=1

aria_recover_options=BACKUP,QUICK,FORCE

Scheduled logical backups are the thing this whole recovery process is trying to reconstruct after the fact.

Conclusion

Orphaned InnoDB recovery is stressful because the database can look half alive. Folders and table names may exist while InnoDB refuses to open the table. The reliable path is patient and evidence-based: preserve, recover one table, automate carefully, dump to SQL, verify by re-import, and rebuild a clean final server.

Central lesson: The .ibd file is not the final recovery artifact. The verified SQL dump is.

References

dbsake. (n.d.). frmdump. dbsake 2.1.2 documentation. Retrieved May 10, 2026

DigitalOcean. (2022, November 1). How to fix corrupted tables in MySQL. DigitalOcean Community.

MariaDB Foundation. (n.d.-a). InnoDB recovery modes. MariaDB Server Documentation. Retrieved May 10, 2026,

MariaDB Foundation. (n.d.-b). InnoDB file-per-table tablespaces. MariaDB Server Documentation. Retrieved May 10, 2026

MariaDB Foundation. (n.d.-c). mariadb-dump. MariaDB Server Documentation. Retrieved May 10, 2026

Oracle. (n.d.-a). Importing InnoDB tables. MySQL 8.4 Reference Manual. Retrieved May 10, 2026

Oracle. (n.d.-b). InnoDB startup options and system variables. MySQL Reference Manual. Retrieved May 10, 2026

Plesk. (2025, April 24). How to fix InnoDB corruption cases for the MySQL/MariaDB databases on Plesk for Windows. Plesk Help Center.

Subscribe to our newsletter!

Dimitrios S. Sfyris https://aspectsoft.gr

Dimitrios S. Sfyris is Founder of AspectSoft and a seasoned professional with 17 years of experience across software development, academic research, and enterprise practice. Holding an M.Sc. in Systems Engineering and a Ph.D. in Fuzzy Logic and Expert Systems, he bridges rigorous academic insight with real-world innovation, specializing in full-stack web applications, SaaS platforms, and scalable API architectures.

Thanasis Koufos https://www.thanasis-codes.eu

MSc in Information Systems (Software Engineer) with a strong security mindset shaped by 17+ years as an Army Officer, now transitioning into Cyber Security. I am advancing through cybersecurity training and certifications while applying Web Development, Software Development, and IT skills in real projects. My goal is to leverage my operational security background and build new, industry-aligned capabilities to complete my shift into the Cyber Security field.

You May Also Like

More From Author

+ There are no comments

Add yours