DiggingIntoWordPress

by Chris Coyier & Jeff Starr

Create a Custom Database Error Page in WordPress

Posted by on

As a dynamic blogging system, WordPress consists of PHP files (the WP core) that interact with a MySQL database to generate the web pages for your website. When everything is working properly, this dynamic interaction keeps WordPress humming along like a champ, but when your database crashes, WordPress can’t operate and will deliver the following message to your visitors:

[ Screenshot: Default WordPress Database Error Message ]

The question is, could this information help an attacker who has targeted your site? This type of specific information should be going to you, the site administrator — not announced to the entire world. Besides, that message really isn’t helping anyone. To the average visitor, it just means the site is borked and that it’s time to move on to someplace else. And to you, the site Admin, the default error message doesn’t mean anything unless you’re lucky enough to be sitting there looking at your site when it happens. I think it’s safe to say that the default database error message:

  • is ugly
  • is useless to visitors
  • is useless to site admins
  • reveals sensitive information

Fortunately, we can improve on all these areas by creating and implementing our own custom database error page. In this article, you’ll learn how to setup your own error page and add some server-side functionality that will improve your ability to respond to database problems as soon as they happen.

How it works

Basically, it all happens automatically: whenever WordPress is unable to connect to the database, it will check for the presence of your custom error page and then serve it up to your visitors; otherwise, if a custom error page is not present, the default error page is displayed. It’s that simple.

How to set it up

To create your own database error page, simply create your custom page, name it “db-error.php”, and upload it to the wp-content directory like so:

wp-content/db-error.php

That’s pretty much all there is to it. Most of the action happens behind the scenes depending on how you set things up. Because this is an actual PHP file, you can implement just about any non-database functionality, along with whatever markup and CSS you desire.

So, now that we know the dark secrets that make this work, let’s look at an actual example..

An actual example of a custom database error page

Here is the code that I use at Perishable Press:

<?php // custom WordPress database error page tutorial @ digwp.com

	header('HTTP/1.1 503 Service Temporarily Unavailable');
	header('Status: 503 Service Temporarily Unavailable');
	header('Retry-After: 3600'); // 1 hour = 3600 seconds
	mail("spamless@domain.tld", "Database Error", "There is a problem with teh database!", "From: Montgomery Scott");

?>
<!DOCTYPE HTML>
<html dir="ltr" lang="en-US">
	<head>
		<title>503 Service Temporarily Unavailable</title>
		<style type="text/css">
			h1, p {
				font-family: Helvetica, sans-serif;
				font-size: 24px;
				color: #333;
				}
			p {
				font-size: 14px;
				}
		</style>
	</head>
	<body>
		<h1>Captain, the ship can&rsquo;t take much more of this!</h1>
		<p>Perishable Press is currently experiencing technical issues &mdash; Please check back soon!</p>
	</body>
</html>

Simple, yes, but more effective than the default error page at facilitating a rapid response. Again, because this is a regular PHP file, we can do just about anything with it — more functionality, elaborate design, etc. — but before we look at some ideas, let’s browse the basics of this file:

The PHP (before the markup)

  • Send a 503 server response to let the client know that they should try back later
  • Send a 503 status response to let the client know that they should try back later
  • Send a Retry-After header to tell the client when to try again (specified in seconds)
  • Send an email to the site admin letting them know that “There is a problem with teh database!”

The HTML markup

  • HTML 5, baby!
  • Give it a title, might as well call it what it is
  • Add some CSS to make it all sweet
  • Throw down some custom markup and tell the user what’s up

From here, you can do just about anything. The PHP stuff is important to let robots and yourself know about the issue, and the markup is important for your human guests. For them, you may integrate your site’s design as much (or as little) as desired. There really is no reason to get too fancy because ideally the page will be displayed for only a brief period. But I suppose if you’re hosted on a crappy server you may want to pimp it out more fully ;)

In any case, here are some more ideas and tips for customizing your own database error page:

  • Make it more official with your logo and other branding embellishments
  • Link to some useful resources, perhaps some static stuff not dependent on the database (RSS Feed?)
  • Don’t disclose the specific issue (i.e., database) — keep it general, like “technical issues” or whatever
  • If your database is down for awhile, save some bandwidth by keeping this file as small and optimized as possible

It would be so cool if..

As it currently stands, this custom database error page is going to send you an email every single time any WordPress page is requested while the database is down. Especially for highly trafficked sites, this could result in thousands of emails flowing into your inbox. On smaller sites, this isn’t really that big of an issue, but for larger sites it would be cool to get a script that would send only one email for each time the database went down. One way to do this would be to use fwrite to alter a static file with some specific text and then check for it before sending the next email, but this would require all sorts of fiddling that seems extraneous. I’m sure there is a better way of doing it.

Last words

Hopefully this post gives you some ideas of what’s possible with your own custom database error pages. It’s nice that WordPress makes them so easy to set up and customize. Even better, because the db-error.php page is located in the wp-content directory, it is not modified or removed during the upgrade process. So just fix it and forget it. Definitely worthwhile to improve your site’s overall visitor experience.

17 Responses

  1. Very cool, thanks a lot :)

  2. Yeah, this is a good idea. Sorta surprised I have never heard about this before, but I’m liking the concept.

  3. Great Tid bit thanks a lot!

  4. Steve Robillard November 30, 2009

    Chris what plugin are you using for code syntax highlighting I love how it expands on mouseover. I would love to check it out for my newe blog on cloud computing.

  5. Definitely helpful! I have been wondering recently if there was a good way to do that.

    Great job, Starr!

  6. D’ouh! I needed that 2 hours ago, when my db was down ^-^ well, i will put that in right away! Cool!

  7. Alright Thanks for the Tut. But, do you know why that happens “Database error”.

  8. Definitely usefull to set up a professional blog/site with wordpress. Thanks for sharing!

  9. I like wordpress in general, I can’t believe something like this was not implemented on the core itself by wordpress people. There’s so many other things that could be added to the core which will avoid installing additional plugins. Adaptation is the key

  10. Added it to my list of planned hacks for 2.9. I had previously hacked wp-includes/functions.php::dead_db() for lack of a better checkpoint, but your examples are much more comprehensive. Thanks!

  11. Useful information this is, thanks mate

  12. Kishore Mylavarapu January 11, 2010

    Thank you.It really helped for my site.Thanks alot.Great knowledge.

  13. Kishore Mylavarapu January 11, 2010

    I just want to tell you one thing.Why can’t you put social media sharing on your blog.So that we will share it to the entire world.Thank you anyway…

  14. Had this bookmarked to implement and got to it today. I had looked how it works in WP natively and noticed that it uses wrapper functions to handle headers in this situation:

    status_header( 500 );
    nocache_headers();

    First function additionally checks for protocol. Second sets multiply headers to prevent caching in all browsers.

Comments are closed. Contact us with any critical information. Thank you!

Code is poetry