قراءة 8 دقيقة

The corrupted WordPress db.php dropin nobody warned you of

WordPress says the DB connection is down but MySQL is fine, and only one site is affected. The cause is almost always a broken db.php dropin in wp-content.

The corrupted WordPress db.php dropin nobody warned you about

The ticket reads "Error establishing a database connection". You SSH into the box. MySQL is up. mysql -u root -p works. The other twelve WordPress sites on the same server are loading fine. Only this one site is broken, and only with that one specific message, and nothing in the server log explains why.

This is one of those incidents that wastes an hour every time we forget about it. The cause is almost always the same and it has almost nothing to do with the database: a corrupted, mis-owned, or stale db.php file in wp-content. WordPress is not failing to talk to MySQL. WordPress is failing to load a dropin file that it found, decided to use instead of its core connection logic, and then could not execute.

This post is the short version of the use case. What a dropin actually is, the sixty-second check, the one-line fix, and the four ways it gets corrupted in the first place.

The symptom in detail

The standard "Error establishing a database connection" page comes from wp-includes/load.php when core's wpdb class cannot connect. The reflex is to blame MySQL. On a multi-tenant cPanel server that reflex is wrong about half the time; the other half it is a dropin.

The tell is the same short list every time:

  • mysql -u root -p from the shell works
  • systemctl status mariadb (or mysqld) shows the service active
  • Other WordPress sites on the same server load normally
  • The credentials in wp-config.php are unchanged from yesterday
  • The site's own database is reachable using those exact credentials if you run mysql -u <wp_user> -p <wp_db> from the cPanel user shell and try a SELECT 1

If all five are true and the WordPress page still says it cannot connect, check wp-content/. Not wp-config.php. Not the database. The dropins directory.

What a WordPress dropin actually is

A "dropin" is a specific small set of file names that WordPress core looks for in wp-content/ on every page boot. If one exists, core loads it and uses it in place of the default behaviour for that subsystem. It is not a plugin, it is not registered through the admin, it does not appear in the Plugins screen. It is loaded by core if and only if the file exists at the right path.

The four that show up in agency-shaped incidents are:

  • wp-content/db.php: replaces the default wpdb database connection class
  • wp-content/object-cache.php: replaces the default object cache
  • wp-content/advanced-cache.php: page cache loaded before most of WordPress
  • wp-content/maintenance.php: replaces the default "briefly unavailable" page

db.php is the one this post is about because it is the one whose failure mode masquerades as a MySQL outage and gets the on-call engineer chasing the wrong problem.

Almost every caching or database-optimisation plugin installs a db.php. W3 Total Cache installs one for query caching. LiteSpeed Cache installs one. Redis Object Cache installs one (or installs object-cache.php, depending on version). Activating the plugin copies the file into wp-content/db.php. Deactivating, if the plugin is well-behaved, removes it. When the plugin is updated incompletely, removed sloppily, or the file gets corrupted by some other process, you get the symptom in this post.

The sixty-second check

Three commands. From the cPanel user shell, in the document root of the affected WordPress install:

# is there a db.php at all?
ls -la wp-content/ | grep -E 'db\.php|object-cache\.php|advanced-cache\.php'
 
# who owns it, and can the PHP process read it?
stat wp-content/db.php
 
# whose plugin claims it?
head -20 wp-content/db.php

The ls -la answers "does the file exist". On a healthy install with no caching dropin, the answer is no. On a site running W3 Total Cache or LiteSpeed Cache or Redis Object Cache, the answer is yes and that is expected.

The stat answers the next-most-common cause: ownership. PHP-FPM under cPanel runs as the cPanel user (for example, goldenvi). The dropin needs to be readable by that user. If someone has done a chown nobody:nobody somewhere up the tree, or if a backup restore handed the file back with root:root permissions, the PHP process cannot read it and WordPress falls into a fatal error path that, depending on the WordPress version, presents as the generic database-connection error.

The head answers which plugin owns the dropin. Every well-behaved caching plugin ships a db.php with a header comment that names the plugin:

<?php
/**
 * Plugin Name: W3 Total Cache Database Cache Drop-In
 * Version: 2.x.x
 * Author: BoldGrid
 *
 * This is a drop-in installed by W3 Total Cache. Do not edit.
 */

If the file is zero bytes, or the first twenty lines are garbage, or the file is full of base64-encoded blobs that look nothing like a plugin header, you have your answer. The dropin is the problem.

The fix

One line. From the cPanel user shell, in the document root:

mv wp-content/db.php wp-content/db.php.bak

That is it. Move the file aside (do not delete it; you may want to look at it later), reload the site. WordPress will not find a dropin, will fall back to the core wpdb connection logic, and will connect to MySQL using the credentials in wp-config.php. The error page disappears.

If the site still does not load, the problem is not the dropin. Go back to checking MySQL, the credentials, and the network path from the PHP process to the database socket. In our experience this is a roughly 90% hit rate fix for the specific symptom at the top of this post.

One caveat. If the site actually depends on the dropin (a high-traffic site on Redis Object Cache, for instance) then moving it aside fixes the connection error but leaves the site running without its cache. Pages will load, possibly slowly. Once the site is up, log into the WordPress admin, deactivate the cache plugin, and reinstall it cleanly. A clean install writes a fresh db.php and the site goes back to using the cache.

Why this happens: four common causes

We have walked into this in roughly equal proportions from four root causes. Each has a different prevention.

Partial-write plugin update. The most common. The site owner clicks "update" on a caching plugin. The update copies a new db.php into wp-content/. The copy is interrupted partway (disk full, PHP timeout, opcache reload at the wrong moment) and the resulting db.php is truncated. WordPress loads it on the next request, hits a parse error, and the parse error surfaces as the connection error because of where in core's boot sequence the dropin loads.

Prevention: monitor free space on the partition holding /home, monitor PHP-FPM error logs, and never run WordPress auto-updates without a disk-space precondition.

Broken file ownership. Someone runs a sweeping chown on the account, possibly during a server migration, possibly while trying to "fix permissions" after a different issue. The dropin ends up owned by root:root or nobody:nobody. PHP-FPM, running as the cPanel user, cannot read it.

Prevention: any chown on a cPanel home directory uses the form chown -R goldenvi:goldenvi /home/goldenvi/public_html/, preceded by a quick ls -la to confirm the current owner is what you expect.

Manual edit by a well-meaning third party. A developer with SFTP access decides to "improve performance" by editing db.php directly. They add a comment, save with a different line ending, or break a quote. The file no longer parses.

Prevention: tell every developer with access that dropins are not to be edited by hand. If a caching plugin needs configuration, configure it through its admin UI. The dropin is generated by the plugin and overwritten on update; any hand edit is going to be lost or going to break.

Stale backup restore. A backup brings back an old db.php whose version no longer matches the currently installed plugin. The dropin tries to call into a runtime that has changed and the load fails.

Prevention: after restoring wp-content, run the cache plugin's "reinstall dropin" routine (most plugins expose one) or just deactivate and reactivate the cache plugin to force a fresh write.

The 60-second check, summarised

For when you bookmark this and come back at 02:30 mid-incident:

# 1. confirm MySQL is fine
mysql -u root -p -e 'SELECT 1;'
 
# 2. confirm the dropin exists and look at it
ls -la wp-content/ | grep db.php
stat wp-content/db.php
head -20 wp-content/db.php
 
# 3. move it aside, reload the site
mv wp-content/db.php wp-content/db.php.bak

If step 3 fixes the site, the dropin was the problem and you have a db.php.bak to inspect later. If not, the dropin was a red herring; restore the file and debug MySQL, credentials, and the socket path properly.

For the broader pattern of WordPress symptoms that point at one layer and resolve at another, the three real WordPress compromises postmortem is worth a read; two of the three cases there started with a symptom that pointed at the database layer and resolved elsewhere. For a tighter reference on wp-content ownership and which files are safe to chmod, the wp-content permissions quick reference

has the canonical table.

How ServerGuard handles this

This is one of our WordPress-hardening use cases.

Detection. ServerGuard runs a scheduled file-integrity check across every managed WordPress install's wp-content/ directory. The check includes a specific routine for the four dropin file names (db.php, object-cache.php, advanced-cache.php, maintenance.php). For each dropin present, the platform records the file's hash, ownership, and the plugin header from the first twenty lines. On every subsequent scan, any of three conditions raises a Safe-tier alert: the file's hash changed without a corresponding plugin update event, the file's owner changed away from the expected cPanel user, or the file's header no longer matches a known caching plugin's signature (which is the signal for a hand edit or a stale restore).

Detection. ServerGuard correlates "Error establishing a database connection" patterns in the WordPress error log or in the PHP-FPM error log against MySQL service state. When the WordPress error appears but MySQL is up, healthy, and serving other accounts, the platform raises a Safe-tier alert that specifically names the dropin as the likely cause. A connection error against an up MySQL is a much narrower problem than a connection error in general.

Remediation, Moderate tier, requires approval, upcoming roadmap. Renaming a corrupted dropin to db.php.bak as the first-line recovery action is a Moderate-tier action routed through the Telegram or web approval flow. The on-call engineer sees the exact file, the rename target, and which of the three detection signals fired. The approval flow itself ships today; the catalogue of dropin-related approvable actions is upcoming.

Out of scope. ServerGuard does not modify WordPress files autonomously. Even when the dropin is clearly broken, the rename requires a human approval, because the dropin may be load-bearing for a high-traffic site and the consequence of moving it aside on a Redis-backed site is a measurable performance change. That is a decision a human should make per site. The platform does not reinstall the plugin that owns the dropin either.

The point is the same as the point of the post: next time WordPress says the database connection is down and MySQL is clearly up, the right first check is not the database. It is ls -la wp-content/ | grep db.php. We forget that. The platform should not.

شارك هذه المقالة

XLinkedInEmail
  • قراءة 6 دقيقة

    When you have to suspend a WooCommerce client: anatomy

    Anatomy of a forced suspension on a shared cPanel server The decision to take a paying client offline to protect fourteen other paying clients is the worst part of running a small hosting agency. There is no scripted version of it that feel

  • قراءة 14 دقيقة

    Patchman activation breaks PHP sites: memory_limit gotcha

    Patchman activation breaks PHP sites: memorylimit gotcha The ticket landed mid-morning. Thirteen WordPress sites on were intermittently returning 500s. Not all at once, not on a clean five-minute beat, not correlated with traffic. The sites

  • قراءة 16 دقيقة

    Three real WordPress compromises and how we found them

    Three real WordPress compromises and how we found them This post is for the people who manage ten to fifty WordPress sites on one or two cPanel boxes, do not have a dedicated security engineer, and keep finding that the malware scanner subs