InnoDB corruption usually appears as error 1712, "Database page corruption on disk or a failed file read", or a server that refuses to start after a power loss or a full disk. You cannot repair a corrupted InnoDB table in place the way you can with MyISAM — the recovery path is to get the server running, dump everything still readable, and rebuild the tables from that dump. This guide walks through that sequence on a Linux VPS, from confirming the damage to a clean import.
Before you start
You need:
- Root or
sudoaccess to the VPS, and a MySQL or MariaDB server that is installed but not necessarily running. - Free disk space at least the size of your data directory, so you can keep a copy of the broken files.
- Your most recent logical backup, if you have one. Recovery is much faster when you can fall back to it.
- The data directory path. On Ubuntu, Debian, AlmaLinux and Rocky it is normally
/var/lib/mysql. Check where my.cnf lives if you are unsure about your layout.
Warning: Do not run any repair or import against the only copy of your data. Copy the data directory first, and keep the copy until you have verified the rebuilt database.
If MySQL will not start at all, you can still reach the VPS through the browser console in your VPS provider's control panel and work from there.
Confirm the damage with CHECK TABLE
Start by finding out which tables are actually broken. If the server is running, run mysqlcheck across everything:
sudo mysqlcheck -u root -p --all-databasesHealthy tables report OK. Anything else — Table is marked as crashed, Incorrect key file, Got error 176 — is a candidate. For a single table:
CHECK TABLE appdb.orders;Then look at the engine state and the error log:
SHOW ENGINE INNODB STATUS\GRead the LATEST FOREIGN KEY ERROR and page-corruption sections. In parallel, watch the log while you query:
sudo tail -n 100 /var/log/mysql/error.log
sudo journalctl -u mysql -n 100 --no-pagerCorruption messages name the tablespace file, for example appdb/orders.ibd, which tells you exactly which table to prioritise.
Stop writes and copy the data directory
Warning: Stop MySQL before copying files. Copying a live InnoDB data directory can produce a copy that is just as broken as the original.
sudo systemctl stop mysql
sudo mkdir -p /root/mysql-corrupt-$(date +%F)
sudo rsync -aH --info=progress2 /var/lib/mysql/ /root/mysql-corrupt-$(date +%F)/If the server will not start, this copy is your working source. If it will start, you still want it — the recovery steps below modify the data directory.
Repair corrupted MySQL InnoDB tables with innodb_force_recovery
innodb_force_recovery tells InnoDB to skip parts of its normal startup checks so the server can come up and let you read data. Levels run from 1 to 6, and you should use the lowest level that lets the server start.
Edit your config file — usually /etc/mysql/mysql.conf.d/mysqld.cnf on Ubuntu and Debian, or /etc/my.cnf.d/mysql-server.cnf on AlmaLinux and Rocky:
[mysqld]
innodb_force_recovery = 1Then start the service and watch the log:
sudo systemctl start mysql
sudo tail -f /var/log/mysql/error.logIf startup still fails, stop the service, raise the value to 2, then 3, and so on. What the levels mean in practice:
1skips corrupt pages instead of crashing.2prevents background purge activity.3skips transaction rollback.4and above make InnoDB read-only, so you can only read and dump.5and6skip undo log and redo log processing — last resort before restoring a backup.
Note: MariaDB uses the same variable name and the same levels. Never leave innodb_force_recovery set once recovery is finished; it disables safety checks and writes.
Dump what you can still read
With the server up, take a logical dump immediately. This is the data you will rebuild from.
mysqldump -u root -p \
--single-transaction --routines --triggers --events \
--databases appdb > /root/appdb-recovered.sqlIf the dump aborts on one bad table, dump table by table and skip the problem:
mysqldump -u root -p --force --databases appdb > /root/appdb-partial.sqlOr pull a single table's rows without its schema:
mysqldump -u root -p --no-create-info appdb orders > /root/orders-data.sqlAt recovery level 6 you may only be able to export rows, not the full schema. In that case, recreate the table structure from your application's migrations or from a schema-only dump, then load the rows.
Rebuild the tables
Once the dump is safe, take the server out of recovery mode and rebuild.
Warning: The next step drops and recreates the database. Confirm the dump file exists and is non-empty before you continue.
sudo systemctl stop mysqlRemove the innodb_force_recovery line from your config file, then:
sudo systemctl start mysqlRecreate the schema and import:
mysql -u root -p -e "DROP DATABASE IF EXISTS appdb; CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -p appdb < /root/appdb-recovered.sqlFor a single damaged table you can sometimes rebuild it in place instead, which keeps the rest of the database untouched:
ALTER TABLE appdb.orders ENGINE=InnoDB;That only works if the table is readable at the current recovery level. If it errors, fall back to the dump-and-import route.
Check it works
Run the integrity check again across all databases:
sudo mysqlcheck -u root -p --all-databasesEvery table should report OK. Then:
- Compare row counts on your largest tables against the dump or your last backup:
SELECT COUNT(*) FROM appdb.orders;- Watch the error log for new corruption messages while your application runs its normal queries:
sudo tail -f /var/log/mysql/error.log- Run a few representative application queries and confirm the results look right, not just that they return.
Troubleshooting
- "Table doesn't exist in engine" — the
.ibdfile is missing or orphaned. Check the data directory for the file, and if it is gone, restore that table from a backup. - Server still will not start at level 6 — the redo log or system tablespace is damaged beyond in-place recovery. Restore from a physical or logical backup and re-apply recent changes.
- mysqldump stops with "Lost connection to MySQL server" — a table is unreadable at the current level. Raise
innodb_force_recoveryby one, or dump with--forceand accept that one table is missing. - Duplicate entry errors during import — the dump already contained the rows. Drop and recreate the schema before importing, as shown above.
- "Cannot add or update a child row" on import — foreign keys are being enforced out of order. Import with
SET FOREIGN_KEY_CHECKS=0;at the top of the session, or use--single-transactionso tables load in dependency order. - Access denied for user 'root' — see fixing MySQL error 1045.
Next steps
- Back up and restore MySQL databases with mysqldump — build the backup you will wish you had next time.
- Restore a MySQL database from a mysqldump file — the import side in more detail.
- MySQL point-in-time recovery using binary logs — replay changes lost between your backup and the crash.
- Automating MySQL backups with mysqldump and cron — make recovery a routine, not an emergency.
