debug_ghosts-6

Debug Ghosts, Part VI

January 04, 2026

How a single Aria checksum error masqueraded as a PHP, PDO, and permissions failure


The Symptom That Wouldn’t Stay Fixed

This was one of those bugs I’d seen before — the kind that never quite goes away.

On Windows (XAMPP), my local TFOL instance would suddenly refuse to connect to the database:

SQLSTATE[HY000] [1045] Access denied for user 'Geoff'@'localhost'

Classic permissions error.
And yet…

  • The user existed

  • The password was correct

  • Privileges were granted

  • phpMyAdmin mostly worked — until it didn’t

Clicking Privileges in phpMyAdmin reliably triggered a deeper error:

#1030 - Got error 176 "Read page with wrong checksum" from storage engine Aria

That message turned out to be the key.


The False Trail: Everything Looked Like Permissions

At first glance, everything pointed in the wrong direction:

  • PDO error → must be credentials

  • phpMyAdmin login works → user exists

  • Grant tables look fine → privileges must be correct

  • Recreating users → no effect

  • Matching passwords → no effect

This was the classic Debug Ghost pattern:

Every fix appeared to work — until it didn’t.

The mistake would have been reinstalling XAMPP (again).
Instead, I stopped and asked a better question:

What if the database is lying to me?


The Real Culprit: Aria System Table Corruption

MariaDB (used by XAMPP) stores many system tables using the Aria storage engine — including tables that power:

  • users

  • privileges

  • roles

  • phpMyAdmin’s Privileges UI

When those tables are corrupted, you get phantom failures:

  • users appear to exist

  • grants appear correct

  • authentication randomly fails

  • admin tools partially work

The smoking gun appeared during repair attempts:

info     : Wrong CRC on datapage at 21815
info     : Wrong CRC on datapage at 21816
...
warning  : Number of rows changed from 4 to 1
status   : OK

That’s Aria saying:

“I found corruption. I fixed what I could. Some rows are gone.”

And those missing rows?
They were privilege-related.


The Fix (The Right Way)

Step 1 — Protect the real data

Before touching system tables, I backed up what mattered:

.\mysqldump -u root -p focus_local > C:\temp\focus_local_backup.sql

SQL dumps of system databases failed — another clue.


Step 2 — Repair the MySQL system database directly

.\mysqlcheck -u root -p --host=127.0.0.1 --port=3306 mysql --auto-repair --extended

This was the turning point.

Every mysql.* table returned:

OK

For the first time in a long time, phpMyAdmin Privileges loaded cleanly.


Step 3 — Recreate users after repair

Because corruption had altered row counts, users and grants were re-stamped:

DROP USER IF EXISTS 'Geoff'@'%';
CREATE USER 'Geoff'@'%' IDENTIFIED BY '********';
GRANT ALL PRIVILEGES ON focus_local.* TO 'Geoff'@'%';
FLUSH PRIVILEGES;

Step 4 — Normalize the connection (Windows matters)

On Windows, ambiguity causes trouble.
The final DSN was made explicit:

mysql:host=127.0.0.1;port=3306;dbname=focus_local;charset=utf8mb4

No localhost.
No guessing.


The Moment of Truth

  • TFOL logged in ✔

  • phpMyAdmin Privileges loaded ✔

  • No more 1045 errors ✔

  • No reinstall ✔

  • No data loss ✔

A bug that had lingered for years was finally gone.


Lessons Learned (Debug Ghosts Rule #6)

  1. Permissions errors can be lies

  2. If admin tools error, believe them

  3. Aria corruption creates phantom bugs

  4. Back up data, then repair system tables

  5. Never reinstall before repairing

  6. On Windows, always specify host + port


Epilogue

This wasn’t a PHP bug.
It wasn’t a PDO bug.
It wasn’t even a permissions bug.

It was a corrupted database pretending to be healthy — and that’s the most dangerous kind of Debug Ghost there is.




Posted in ghost-stories by TFOL BLOG

Comments