Your site worked ten minutes ago. Now every page shows one flat grey line: “Briefly unavailable for scheduled maintenance. Check back in a minute.”
The WordPress maintenance mode error looks like a crash. It is not. A single hidden .maintenance file in your site root is holding the whole thing behind a 503 response.
Deleting it takes about two minutes over FTP. Knowing why the update died in the first place takes slightly longer, and skipping that part is how people end up back here next month.
What follows covers:
- What the flag file contains and why core writes it
- Fixes through FileZilla, cPanel, WP-CLI, and hosting dashboards
- Cache layers that keep serving the 503 after deletion
- Finishing the interrupted update and preventing a repeat
What Is the WordPress Maintenance Mode Error?
WordPress maintenance mode error is a 503 Service Unavailable state caused by a leftover .maintenance file in the site root. Visitors see one flat line of text: “Briefly unavailable for scheduled maintenance. Check back in a minute.” The site is not broken. It is locked.
The lock is enforced by wpmaintenance(), which lives in wp-includes/load.php and runs on every single request before plugins or your theme load.
No database query fires. No theme loads. About a dozen core files get pulled in and nothing else, which is exactly why that page looks so bare.
| WordPress Component | Location | Purpose |
|---|---|---|
.maintenance | WordPress root directory (alongside wp-config.php) | A temporary flag file that tells WordPress to display the maintenance mode message during updates. |
wp_maintenance() | wp-includes/load.php | Checks whether maintenance mode is active, sends an HTTP 503 Service Unavailable response, and stops normal page execution. |
WP_Upgrader::maintenance_mode() | wp-admin/includes/class-wp-upgrader.php | Creates the .maintenance file before updates begin and removes it automatically when the update completes successfully. |
Worth separating this from its lookalikes early. A blank page with no message at all is the blank screen problem that follows a PHP fatal error, not a maintenance lock.
The maintenance screen always carries text. That single detail tells you which problem you have before you touch a file.
Have you seen the latest WordPress statistics?
Discover the latest WordPress statistics: market share, security trends, performance data, and revenue insights that shape the web.
Check Them Out →What the .maintenance File Contains
One line of PHP. Nothing else.
<?php $upgrading = 1735838412; ?>
$upgradingholds the Unix timestamp of the moment the update began- File size is under 30 bytes
- Open it before deleting it, since that timestamp tells a support engineer exactly when the update died
Why the Error Returns a 503 Status Code
Status sent: HTTP 503 Service Unavailable, issued through wpdie() with a 503 response argument.
Header attached: Retry-After: 600, telling clients and crawlers to come back in 10 minutes.
WP Remote confirmed this on a clean WordPress 6.9.4 install: an active .maintenance file returned 503 with Retry-After: 600.
A 503 is temporary by definition, which is why this specific server response signals downtime rather than failure.
What Causes WordPress to Get Stuck in Maintenance Mode?
The update process died before it reached the cleanup step. WPUpgrader writes .maintenance before extracting a single byte of the new package, then deletes it after every file lands. Kill the script in between and the flag file survives.
Nine times out of ten, the killer is a resource ceiling rather than a bug.
| Cause | What Happens | Common Trigger |
|---|---|---|
| PHP Execution Timeout | The update process stops before it finishes extracting and installing files, leaving the update incomplete. | max_execution_time is too low (commonly 30 seconds on shared hosting). |
| PHP Memory Exhaustion | WordPress encounters a fatal error while processing the update because it runs out of available memory. | A low PHP memory limit (for example, 64 MB) on shared hosting. |
| Bulk Plugin or Theme Updates | Multiple updates running in succession increase the likelihood of interruptions or resource exhaustion. | Updating many plugins or themes simultaneously. |
| Fatal Error in Updated Code | The update process aborts before cleanup completes, potentially leaving the site in maintenance mode. | Incompatible PHP version, plugin conflicts, or code errors introduced by the update. |
WordPress ships with WPMEMORYLIMIT at 40M for single-site installs and 64M for multisite, which is conservative to the point of being a liability on any site running a page builder.
That default is the same reason people run into the allowed memory size exhausted message during large updates.
Version drift makes it worse. Censys examined over 316,500 publicly visible WordPress deployments in 2026 and found only 30% running a supported PHP version, with most still on PHP 7.4, which hit end of life in November 2022.
Plugin volume is the other half of the story. US WordPress sites average 21 active plugins each (SQ Magazine, 2025), and Patchstack recorded 11,334 new ecosystem vulnerabilities in 2025, with 91% of them in plugins. More plugins means more update events, and every update event is a chance for a request that never finishes in time.
How Long Does WordPress Maintenance Mode Last?
Ten minutes, maximum, by design. wpismaintenancemode() compares the $upgrading timestamp against the current time and returns false once the gap reaches 10 MINUTEINSECONDS. A clean update holds the lock for 5 to 30 seconds.
The core check is one line: if ( ( time() - $upgrading ) >= 10 MINUTEINSECONDS ) { return false; }
So the safety valve exists. Most guides skip it entirely, which is odd, because it means a fair number of “stuck” sites clear themselves while the owner is still hunting for an FTP password.
When the timer does not save you:
- Repeated failed update attempts keep rewriting the file with a fresh timestamp
- A caching layer is serving a stored copy of the 503 response
- A maintenance plugin is holding the site down independently of core
Past the ten-minute mark with the message still showing, the site is genuinely locked rather than mid-update and needs manual work.
How to Fix the WordPress Maintenance Mode Error by Deleting the .maintenance File
Delete .maintenance from the site root. The root is the folder holding wp-config.php, wp-admin, wp-content, and wp-includes, usually named publichtml. Removal takes effect on the next request with no restart and no cache flush required at the server level.
Back up first. Not because deleting one flag file is risky, but because whatever crashed the update is still sitting there unresolved.
Deleting via FTP (FileZilla, Cyberduck)
The file starts with a dot, so it is hidden by default and half the people who look for it swear it does not exist.
- FileZilla: Server > Force showing hidden files
- Cyberduck: View > Show Hidden Files
- Open the root folder, right click
.maintenance, delete
Then hard refresh with Ctrl+F5 on Windows or Cmd+Shift+R on Mac.
Deleting via cPanel or Plesk File Manager
cPanel: open File Manager, click Settings in the top right, tick “Show Hidden Files (dotfiles)”, then navigate to publichtml.
Plesk: the equivalent toggle sits under the hamburger menu inside File Manager.
Faster than FTP for a one-file job, and it avoids the credential hunt entirely. This is the route I take on client sites where I do not already have SFTP keys set up.
Deleting via SSH and WP-CLI
WP-CLI ships with a dedicated command, no file hunting involved:
wp maintenance-mode deactivate
If that errors out, drop to the shell: rm /path-to-root/.maintenance
Check the result with wp maintenance-mode status, which returns “Maintenance mode is not active” when the lock is gone.
Deleting via Hosting Dashboard File Tools
| Hosting Provider | Where to Check |
|---|---|
| WP Engine | Environment Overview → Utilities → Maintenance Mode toggle |
| Kinsta | MyKinsta → Tools, or connect via SSH and use the preinstalled WP-CLI |
| SiteGround | Site Tools → File Manager to locate and remove the .maintenance file or manage your WordPress installation |
WP Engine’s portal toggle runs WP-CLI underneath and self-deactivates after 10 minutes, matching core behavior exactly.
One thing to expect: if the site loads but throws a critical error notice instead of your homepage, the flag file was only the outer layer. Something deeper crashed. There is also a plugin-side switch for turning the mode off when a plugin put the site there deliberately.
How to Fix Maintenance Mode When Deleting the File Does Not Work
The file is gone but the 503 persists, which means something is replaying a stored copy of that response. Cache layers are the usual suspect. Permissions are the second. Both are quick to rule out once you know which layer to check.
| Cache Layer | Common Tools | Recommended Action |
|---|---|---|
| Page Cache | WP Rocket, W3 Total Cache, LiteSpeed Cache | Purge or clear all cached pages and files. |
| Object Cache | Redis, Memcached | Flush the object cache to remove stored database objects. |
| Edge/CDN Cache | Cloudflare, Fastly | Purge the entire CDN cache. If using Cloudflare, enable Development Mode temporarily while testing. |
| Browser Cache | Chrome, Firefox, Safari | Perform a hard refresh, then verify the site again in a private/incognito window to rule out cached browser content. |
Caching is nearly universal now, with 82.4% of WordPress sites running at least one caching plugin (SQ Magazine, 2025). Some CDNs also hold a 503 for several minutes after the origin recovers, so give the edge a moment before assuming the purge failed.
Permissions block: folders should sit at 755 and files at 644. Anything set to 444 stops WordPress from removing its own flag file, and hosts running suPHP can block writes through ownership mismatches rather than permission bits.
If deletion itself is being refused, the fix is correcting ownership and permission values across the install. Your host can reset them in a single command if you would rather not touch it.
Still stuck? Check whether a maintenance mode plugin such as SeedProd or LightStart is active. Those operate through wpoptions, not through .maintenance, so deleting the file does nothing at all.
How to Finish an Interrupted WordPress Update
Removing .maintenance unlocks the site. It does not complete the update that failed. Half-replaced core files, a plugin folder containing two versions, and a skipped database routine all survive the deletion and cause errors later.
Verify what actually landed before assuming the job finished.
Through WP-CLI, one item at a time:
wp core updateto finish an aborted core upgradewp plugin update --allto process plugins sequentially instead of in parallelwp core versionto confirm the running version
Sequential processing matters here. Bulk dashboard updates fire overlapping cycles, and that overlap is what produced the stuck state to begin with.
Manual core replacement: download a fresh copy from WordPress.org, delete wp-admin and wp-includes, upload the new ones, and leave wp-content plus wp-config.php untouched. Content and settings survive intact. It is one of the rare occasions where touching core files is the correct move.
Then visit /wp-admin/upgrade.php directly. That URL triggers the database routine WordPress normally runs on its own after a core update, and skipping it leaves the schema out of sync with the new version.
Check wp-includes/version.php to read the installed version straight from disk. Re-run anything that did not complete, one plugin per click, which also sidesteps the usual failures that surface partway through a plugin upgrade. Broader recovery steps for a botched core upgrade are covered in the guide to problems that appear after a version bump.
How to Identify Which Plugin or Theme Broke the Update
Read the logs. A PHP fatal error names the exact file path and line number that killed the process, which points at a specific plugin or theme folder in one step. Guessing through deactivation is slower and less reliable than reading the log entry.
Turn on debug logging by adding two constants to wp-config.php above the “stop editing” comment:
define( 'WPDEBUG', true );define( 'WPDEBUGLOG', true );define( 'WPDEBUGDISPLAY', false );to keep errors off the front end
Entries land in wp-content/debug.log. Full setup detail sits in the walkthrough on surfacing PHP errors during troubleshooting, and the server-side equivalent is covered under reading the log file your host writes.
Your hosting error log is often faster. cPanel, DirectAdmin, and Plesk all expose one, and the timestamp on the crash will match the $upgrading value you read earlier.
Forcing Plugins Off Without Dashboard Access
Rename wp-content/plugins to plugins-off over FTP. WordPress deactivates every plugin at once and lets you back into wp-admin.
Rename it back, then reactivate one at a time until the fatal error returns. Tedious, effective, and it works when nothing else does.
Tools That Narrow It Down Faster
Health Check & Troubleshooting: disables plugins for your session only, so visitors keep seeing a working site while you test.
Query Monitor: surfaces PHP notices, slow queries, and hook conflicts inside the admin bar.
Patchstack logged 11,334 new WordPress vulnerabilities in 2025, a 42% jump over 2024, with 91% traced to plugins and 9% to themes. That distribution is a decent prior when you are deciding where to look first.
The Usual Offenders
Security plugins, caching plugins, and page builders break updates more often than anything else. Not because they are badly built, but because they hook deeply into core and run their own processes during an update window.
Wordfence sits on over 4.2 million sites and Elementor on more than 10 million active installs, so their update cycles touch an enormous share of the ecosystem. If a theme conflict is the actual root cause, switching to Twenty Twenty-Four for one page load will tell you within seconds.
How to Enable Maintenance Mode Intentionally in WordPress
Create a .maintenance file in the site root holding <?php $upgrading = time(); ?>. Core honors it for 10 minutes from that timestamp. Anything longer needs the enablemaintenancemode filter or a dedicated plugin.
The quirk that trips people up: time() evaluates on every request, so time() - time() always returns 0 and the lock never expires. Hard-code a number instead and it dies after 10 minutes regardless.
| Maintenance Method | Level of Control | Best Use Case |
|---|---|---|
Manual .maintenance File | Basic – Displays WordPress’s default maintenance message with no customization | Quick maintenance during file-level work via SFTP, FTP, or File Manager |
enable_maintenance_mode Filter | Advanced – Can be customized by user role, IP address, or other conditions | Developers who need selective maintenance mode while retaining admin access |
| Maintenance Plugin (e.g., SeedProd or LightStart) | High – Custom landing pages, branding, countdown timers, opt-in forms, and access controls | Client websites, scheduled maintenance, and professional maintenance pages |
The filter approach hooks enablemaintenancemode and returns false for whoever should bypass the lock. Return false when currentusercan('administrator') passes and your team keeps working while visitors see the holding page.
You can gate it by IP address or by hour of day using the same filter. Two arguments come through: $enablechecks and $upgrading.
On the plugin side, SeedProd sits on over 900,000 active installs and LightStart (formerly WP Maintenance Mode) on roughly 600,000. Both let you exclude specific URLs so a landing page stays public while the rest of the site sits behind the screen.
Set the response correctly or you will pay for it later. A maintenance page returning HTTP 200 tells crawlers your real content has been replaced by that placeholder, which is a genuinely bad outcome and the reason a stuck coming soon screen causes so much confusion.
Maintenance mode vs coming soon mode: maintenance mode is for a site that already exists and will return. Coming soon mode is for a site that has never launched, and it usually serves a 200 on purpose because there is nothing indexed to protect. If you want the whole thing offline permanently instead, taking the site down properly is a different job.
Custom Maintenance Page via maintenance.php in wp-content
Drop a file named maintenance.php into wp-content. wpmaintenance() checks for it first and loads yours instead of the default screen.
Watch the headers. Core Trac ticket #57134 flagged that custom maintenance pages exit through die() rather than wpdie(), so they return HTTP 200 instead of 503 unless you send the headers yourself.
Set header( "$protocol 503 Service Unavailable", true, 503 ) and header( 'Retry-After: 600' ) at the top of the file. No database is available at that point, so keep the markup self-contained.
What Impact Does Maintenance Mode Have on Search Rankings?
Short maintenance windows cost nothing. Googlebot treats a 503 as temporary and comes back later. Gary Illyes confirmed at Google Search Central SEO office hours in April 2024 that 10 to 15 minute outages happening several times a week are acceptable.
Duration is the whole story here.
| Outage Duration | Typical Search Engine Behavior |
|---|---|
| Under 1 Hour | Usually no measurable SEO impact. Search engines treat the outage as temporary and retry crawling. |
| Several Hours to 1 Day | Crawl rate may decrease while search engines wait for the site to become available again. |
| Multiple Days | Search engines may begin removing affected URLs from the index, resulting in reduced search visibility until the site is restored. |
Google previously stated it would begin deindexing pages once a site stayed unreachable for more than a few consecutive days. Community guidance in Google’s support threads puts the safe ceiling around 24 hours, with real deindexing risk past seven days.
Retry-After does the heavy lifting. Core sends Retry-After: 600 automatically, and Googlebot uses that value to schedule the next crawl instead of logging a failure.
Google’s own guidance from Search Central goes back to 2011 on this: returning 200 for downtime, bandwidth overruns, or placeholder pages is the mistake, and 503 is the correct answer.
A 200-status maintenance page is worse than a proper 503 for one reason. Google indexes whatever it sees, so your homepage snippet becomes “Briefly unavailable for scheduled maintenance” until the next recrawl. That is the same failure pattern behind a server refusing requests it should be handling and the related capacity message some hosts return under load.
Checking recovery: run URL Inspection in Google Search Console and hit Test Live URL. A 200 response confirms the lock is gone. Crawl Stats under Settings shows whether Googlebot logged 503s during the window and how quickly the rate recovered.
How to Prevent the WordPress Maintenance Mode Error
Raise the PHP ceilings, update in small batches, and test on staging first. Those three changes remove nearly every condition that kills an update mid-process. A full backup beforehand turns a stuck site into a five-minute rollback instead of a recovery project.
Config values worth setting:
define( 'WPMEMORYLIMIT', '256M' );inwp-config.php, above the “stop editing” linedefine( 'WPMAXMEMORYLIMIT', '512M' );for admin and update processesmaxexecutiontime = 300inphp.ini, up from the common 30-second default
The WordPress constants only raise the ceiling. They cannot exceed the server’s own memorylimit, which is where locating the actual PHP config file on your host becomes the real step. cPanel exposes it through MultiPHP INI Editor, Plesk through PHP Settings.
Batch size matters more than most people expect. Ticking 15 plugins and hitting Update runs overlapping cycles that collide. WP-CLI processes them sequentially, which is why wp plugin update --all almost never produces a stuck state on the same server where the dashboard does.
Test on staging. WP Engine, Kinsta, SiteGround, and Cloudways all ship one-click staging environments, and Google explicitly recommends staged rollouts for anything requiring extended downtime.
Back up first, every time. UpdraftPlus runs on more than 3 million sites, and its premium tier triggers a backup automatically before each update, which is the behavior you actually want. BlogVault and host-level snapshots from Kinsta or WP Engine do the same job.
Keep PHP current. Censys found only 30% of publicly visible WordPress installs on a supported PHP version in 2026, with most still on PHP 7.4 (end of life since November 2022). A plugin built for PHP 8.2 throwing a fatal error on 7.4 is a textbook cause of a half-finished update.
Auto-updates cut the manual load. Roughly 80% of WordPress users had core auto-updates enabled as of 2025, and the autoupdateplugin filter lets you allow-list stable plugins while holding page builders and security plugins for manual review. Agencies running dozens of installs usually handle update scheduling across a whole portfolio from one dashboard rather than site by site.
WordPress Maintenance Mode Error vs Other WordPress Downtime Errors
Maintenance mode returns a 503 with one readable sentence and clears the second the flag file goes. White screens, database failures, and 500 errors return different status codes and need entirely different fixes. Read the screen before touching anything.
| Error | What You’ll See | Most Common Cause |
|---|---|---|
| Maintenance Mode | HTTP 503 with a “Briefly unavailable for scheduled maintenance” message | A leftover .maintenance file after an interrupted WordPress update |
| White Screen of Death (WSOD) | A completely blank page, with or without an HTTP 500 response | PHP fatal error, plugin/theme conflict, or exhausted PHP memory limit |
| Error Establishing a Database Connection | A WordPress database connection error message | Incorrect database credentials, unavailable MySQL server, or a corrupted database |
| 500 Internal Server Error | A generic server-generated error page | Invalid .htaccess rules, PHP configuration issues, file permission problems, or server misconfiguration |
Two of these look similar enough to cause wasted hours. A blank page means PHP died before output started, so no message reached the browser. A maintenance screen always carries text, because core deliberately wrote it there.
Credential failures announce themselves clearly, and the message about a failed database link names the problem in the page body. That is not a maintenance lock, and deleting .maintenance will not touch it.
A generic 500 response from the server is different again. The web server generated that page, not WordPress, which is why it usually carries Apache or Nginx branding rather than WordPress styling.
The lookalike that is not a lookalike: “Another update is currently in progress” is a separate lock entirely. It lives in the database, not the filesystem, and it blocks the admin screen instead of the front end.
How to Clear the coreupdater.lock Entry
WordPress writes a coreupdater.lock row into wpoptions when a core update starts, holding a Unix timestamp. Since WordPress 4.5, any lock older than 15 minutes is treated as expired and overwritten on the next attempt.
Fastest route: wp option delete coreupdater.lock
Without SSH, open phpMyAdmin, select the site database, browse wpoptions, filter rows for coreupdater, and delete the matching row.
Back up before touching tables. Editing options directly is safe enough here, though it belongs in the same category as any other manual repair at the database level.
FAQ on WordPress Maintenance Mode Error
Why does my site say “Briefly unavailable for scheduled maintenance”?
An update started and never finished. WPUpgrader wrote a .maintenance file to your site root before unpacking files, then died before deleting it. The leftover flag file keeps every visitor on that screen.
Where is the .maintenance file located?
Site root, the same folder holding wp-config.php, wp-admin, wp-content, and wp-includes. Most hosts name it publichtml. It never sits inside a subfolder unless your WordPress install itself lives in one.
Is it safe to delete the .maintenance file?
Yes. The file holds one line of PHP and no site data. Deleting it unlocks the front end immediately, though it does not finish whatever update failed, so verify versions afterward.
Why can’t I see the file in FileZilla?
Dot-prefixed files are hidden by default. In FileZilla, switch on Server > Force showing hidden files. cPanel File Manager hides them too until you tick “Show Hidden Files (dotfiles)” under Settings.
How long does WordPress stay in maintenance mode?
Ten minutes at most. wpismaintenancemode() compares the $upgrading timestamp against current time and ignores the file past 600 seconds. A normal plugin update holds the lock for 5 to 30 seconds.
Why is the maintenance screen still showing after deleting the file?
Something cached the 503 response. Purge WP Rocket, W3 Total Cache, or LiteSpeed Cache, flush Redis or Memcached, then clear Cloudflare. Test in a private window before assuming the purge failed.
Can I reach wp-admin while the site is locked?
No. wpmaintenance() fires before plugins, themes, or the database load, so the admin area is gone too. Fixing it requires FTP, SSH, a File Manager, or your hosting dashboard.
Does maintenance mode damage search rankings?
Short windows do not. Googlebot reads the 503 plus Retry-After: 600 as temporary and retries. Gary Illyes confirmed in April 2024 that 10 to 15 minute outages are fine. Multi-day 503s risk deindexing.
How is this different from “Another update is currently in progress”?
Different lock entirely. That one is a coreupdater.lock row inside wpoptions, it expires after 15 minutes, and it blocks the dashboard rather than the front end.
How do I stop it happening again?
Raise WPMEMORYLIMIT to 256M and maxexecutiontime to 300. Update plugins one at a time instead of bulk selecting. Run wp plugin update --all through WP-CLI, which processes sequentially.
Conclusion
The WordPress maintenance mode error comes down to one flag file and a ten-minute timer. Delete it, purge the cache, and the site comes back.
What matters more is the step after. Run wp core update, load /wp-admin/upgrade.php, then read debug.log before you call it finished.
Repeat cases almost always trace to the same two numbers: a 30-second maxexecutiontime` and a stock memory ceiling.
Raise both. Then change the habit itself.
One plugin per update, staging before production, and a snapshot from UpdraftPlus or your host before you click anything.
Googlebot forgives a brief 503 without blinking. It stops forgiving somewhere past a day, which is the actual reason speed matters here.


