Skip to content
Skip to main content
Ahosting Logo
  • Hosting
    • WordPress Hosting
      Fast, secure hosting for WordPress sites
    • Web Hosting
      Reliable, affordable hosting for sites
    • FFMpeg Hosting
      Fast hosting for FFmpeg projects
    • Reseller Hosting
      Start hosting biz with white-label plans
    • VPS Hosting
      Scalable VPS with full control & power
    • Dedicated Server
      High-power servers for max security
    • WooCommerce Hosting
      Fast hosting for WooCommerce shops
  • Domain
    • Register a Domain
      Secure your domain name in minutes
    • Domain Transfer
      Move domains to Ahosting with ease
    • Premium SSL Certificate
      Enterprise SSL to build customer trust
  • Support
    • Submit A Ticket
      Expert 24/7 help from our support team
    • Abuse Report
      Report abuse to keep network safe
    • Knowledge Base
      Quick answers via step-by-step guides
  • Company
    • Blog
      Expert articles to power your online growth
    • Compare Hosts
      Side-by-side comparison
    • Datacenter
      Secure, high tech datacenter for hosting
    • About Us
      Learn about our mission, values & team
    • Contact Us
      Contact sales for plans, pricing & advice
    • Sitemap
      Find info fast with our clear site map
My Account
Ahosting Logo
  • Hosting
    • Web Hosting
    • WordPress Hosting
    • FFMpeg Hosting
    • Reseller Hosting
    • VPS Hosting
    • Dedicated Server
    • WooCommerce Hosting
  • Domain
    • Register a Domain
    • Domain Transfer
    • Premium SSL Certificate
  • Support
    • Knowledge Base
    • Abuse Report
    • Submit A Ticket
  • Company
    • About Us
    • Contact Us
    • Blog
    • Sitemap
    • Datacenter
  • Legal
    • Privacy Policy
    • Terms of Service
    • Acceptable Use Policy
    • Service Level Agreement
    • Resource Abuse Policy
My Account

AHosting Blog

Tag: WordPress

  • Installation Failed: Destination Folder Already Exists in WordPress: What It Means and How to Fix It

    Installation Failed: Destination Folder Already Exists in WordPress: What It Means and How to Fix It

    • Installation Failed: Destination Folder Already Exists, Explained
      • What the message looks like
    • Where the Destination Folder Already Exists Check Lives in WordPress Core
      • Why a normal install never clears the folder
    • Why an Empty Folder Passes and a Hidden File Fails: the Lab Results
    • How WordPress Decides When Destination Folder Already Exists Appears
    • Zip Upload Versus Install Now
    • The Destination Folder Already Exists Decoder Table
    • Find Your Destination Folder Already Exists Fix
    • Fix Destination Folder Already Exists From the WordPress Dashboard
    • Fix Destination Folder Already Exists in cPanel File Manager
      • Delete the leftover instead of keeping it inside wp-content
    • When Destination Folder Already Exists Keeps Coming Back
      • Check what keeps writing into the folder
      • Rule out space and permissions first
    • What the Destination Folder Already Exists Lab Did Not Test
    • Still Seeing Destination Folder Already Exists? Send the Exact Message
    • Frequently Asked Questions: Destination Folder Already Exists
      • What does the destination folder already exists error mean in WordPress in 2026?
      • Why does WordPress say destination folder already exists when the plugin is not installed?
      • Can I delete the folder safely when destination folder already exists appears in 2026?
      • Does an empty folder cause the destination folder already exists error?
      • Replace current with uploaded vs deleting the folder: which fixes destination folder already exists?
      • Install Now vs zip upload: which shows the destination folder already exists error differently in 2026?
      • How do I find hidden files that cause destination folder already exists in cPanel File Manager?
      • Can AHosting support look at it when destination folder already exists keeps coming back?
      • What should I send AHosting in 2026 when a plugin install fails with this folder error?
      • Is destination folder already exists a WordPress problem or an AHosting server problem?
    TL;DR

    WordPress stops with Destination folder already exists when the folder it needs is already on disk and is not empty. An empty folder passes; a single hidden file does not. Read the full path in the message, look inside with hidden files shown, then delete or move the leftover and install again. For a zip of a plugin you already have, Replace current with uploaded clears the old folder first, so back up before you click it.

    Listen: WordPress stops an install when the destination folder holds anything, including a hidden file, and a short check tells you which fix applies. By Matt Chrust, Director of Business Development, AHosting.

    Installation Failed: Destination Folder Already Exists, Explained

    WordPress shows Installation failed: Destination folder already exists. when it unpacks a plugin or theme and finds that the folder it needs is already on disk and is not empty. The message ends the install. Nothing is overwritten, and the folder that stopped it stays exactly as it was.

    This guide is for the person who just clicked Install Now or uploaded a zip and got that line. It tells you which folder is in the way, why WordPress treats it as a stop, and the shortest safe fix for each case. Every behavior below was measured on a WordPress 7.1.4 test install, and every core line number comes from that source.

    One finding changes the usual advice. An empty folder does not trigger the error, while a folder holding a single hidden file does. So “delete the folder” is right, but only after you have looked inside it.

    What the message looks like

    The full line reads Installation failed: Destination folder already exists. and is followed by the full path of the folder, for example a path ending in wp-content/plugins/classic-editor/. On a plugin install WordPress adds Plugin installation failed. below it. That path is the most useful part of the message because it names the folder you have to inspect. Copy it before you do anything else.

    Where the Destination Folder Already Exists Check Lives in WordPress Core

    The check sits in WP_Upgrader::install_package() in wp-admin/includes/class-wp-upgrader.php. In WordPress 7.1.4 the decision is on lines 699 to 707. Plugin installs, theme installs and zip uploads all pass through it, and the developer reference for the method documents the argument that controls it: abort_if_destination_exists, which defaults to true.

    In plain words the logic has three branches. If the caller asked WordPress to clear the destination, the old folder is removed and the install continues. If not, and a folder is already there, WordPress reads its contents with dirlist() (line 703). An empty result lets the install continue. Anything else makes WordPress delete its own unpacked copy (line 706) and return the folder-exists error with the folder path attached (line 707).

    Why a normal install never clears the folder

    Both installers default to not overwriting. Plugin_Upgrader::install() sets overwrite_package to false at line 121 of class-plugin-upgrader.php, and the theme installer does the same at line 233 of class-theme-upgrader.php. The plugin installer then passes that value on as clear_destination (line 139). Updates are different: upgrade() asks for the clear at line 228, which is why updating a plugin never raises this error while installing the same plugin over a leftover does.

    Why an Empty Folder Passes and a Hidden File Fails: the Lab Results

    We reproduced the error on a clean WordPress 7.1.4 install, using the Classic Editor plugin and the Install Now button. The lab ran on one workstation with PHP 8.5.10 and a direct filesystem. It was not an AHosting server, and the results below describe WordPress core, not our hosting platform.

    What was inside wp-content/plugins/classic-editorResult of Install NowWhat it shows
    No folder at allInstalledThe normal case
    An empty folderInstalledAn empty listing does not stop WordPress
    One loose file, leftover.txtDestination folder already exists.Any visible file counts
    One hidden file, .htaccessDestination folder already exists.Hidden files count too
    One empty subfolder, jsDestination folder already exists.A subfolder is an entry, even when empty
    Destination folder already exists lab table: WordPress 7.1.4, Classic Editor 1.7.0 through Install Now, one workstation, not an AHosting server.

    Two rows surprise people. The hidden .htaccess file counts because WordPress lists everything in the folder, while many file managers hide names that start with a dot. The same convention exists on the command line, where the ls manual says -a is needed to stop ignoring entries that start with a dot. After every failure the folder in the way was unchanged, so the error never damages what is already there.

    How WordPress Decides When Destination Folder Already Exists Appears

    The diagram below turns the three branches into one question: does the folder hold any entry at all? If it does, the install stops. If it does not, the install goes ahead, whether the folder was missing or merely empty.

    How WordPress decides whether a destination folder blocks an install A three-step flow. First WordPress looks for the destination folder. If it is missing the install goes ahead. If it exists WordPress lists its contents, hidden files included. An empty list lets the install go ahead; anything else stops it with Destination folder already exists. Unpacked plugin needs a folder Folder exists and has any entry, hidden or not? No: missing or empty The install goes ahead Yes: something is there Installation failed Measured on WordPress 7.1.4, one test workstation. ahosting.net

    Zip Upload Versus Install Now

    A zip upload goes through the same check and then does something extra. In our 7.1.4 lab, uploading the same Classic Editor zip twice produced the error line followed by a screen headed This plugin is already installed. It held a table comparing the current and uploaded plugin name, version, author, required WordPress version and required PHP version, and a button labeled Replace current with uploaded. The code that draws it is in class-plugin-installer-skin.php, from line 192, and is marked as added in WordPress 5.5.0.

    The screen appears only when WordPress can find a plugin in that folder. That skin calls get_plugins() (line 201) and gives up if nothing matches. WordPress recognizes a plugin by its main file, and the plugin header requirements say a header must contain at least the Plugin Name field. So a leftover folder with a stray text file gets the bare error and no button. We saw exactly that, and with a theme zip we saw This theme is already installed even though the stray folder was not a working theme.

    If your upload fails earlier, before any unpacking, the message is a different one, and our guide to the missing temporary folder error covers it.

    The Destination Folder Already Exists Decoder Table

    Open the folder named in the error message with hidden files shown, find your row, and follow the fix. The rows are ordered from the most common situation to the least.

    What you find in the folderWhat it usually isFirst fix
    A working copy, listed under Installed PluginsThe plugin is already installedUpdate or delete it from the Plugins screen, or use Replace current with uploaded for a zip
    Files that WordPress does not list as a pluginLeftovers from an earlier attempt, an FTP upload or a restoreBack up, then delete or move the folder
    Only hidden files such as .htaccessA dotfile someone or something wrote thereShow hidden files, back up, delete or move the folder
    Only an empty subfolderA leftover directory structureDelete or move the folder
    Nothing, even with hidden files shownNot this folder, or a stale listingRe-read the full path, refresh, and check again
    You cannot delete or move itThe folder belongs to another user or is lockedOpen a ticket with the full path
    The AHosting Destination Folder Already Exists Decoder Table: what the folder holds, what it usually is, and the first fix.

    Find Your Destination Folder Already Exists Fix

    Choose how you started the install and what the folder holds. The finder returns the matching row of the table above.

    Destination Folder Already Exists Fix Finder

    Choose your two answers, then press the button.
    See AHosting WordPress hosting

    Fix Destination Folder Already Exists From the WordPress Dashboard

    1. Read the full path in the message and note the last folder name. That is the folder in the way.
    2. Open Plugins, then Installed Plugins, and search for that plugin. If it is listed, update it there, or deactivate and delete it, then install again.
    3. If you uploaded a zip and see This plugin is already installed, compare the versions in the table. Replace current with uploaded installs your zip over the old copy.
    4. Back up first. In our lab the Replace button removed every file in the old folder, including a note file we had added, so anything you stored inside a plugin folder is gone afterward.
    5. If you see the bare error with no comparison table, WordPress found no plugin in that folder. Continue with the File Manager steps below.

    Fix Destination Folder Already Exists in cPanel File Manager

    1. Open File Manager, choose Settings, and select Show Hidden Files (dotfiles), as the cPanel File Manager documentation describes. Without this, a folder that holds only a dotfile looks empty.
    2. Browse to the folder named in the error message, usually under wp-content/plugins or wp-content/themes.
    3. Look at what it holds and compare it with the decoder table above.
    4. Create a folder outside wp-content, for example in your home directory, and move the leftover folder into it. The File Manager documentation lists Move and Rename among the toolbar actions.
    5. Run the install again. If it succeeds, delete the moved copy once you are sure you do not need it.

    Delete the leftover instead of keeping it inside wp-content

    Move the folder out rather than renaming it inside wp-content, because WordPress scans that directory for plugins and a renamed copy can still be listed. A leftover plugin is also a security question. One vendor write-up on inactive plugins makes the point that a plugin switched off still leaves its files on the server, where they can be requested directly. So when the leftover is truly unwanted, delete it.

    When Destination Folder Already Exists Keeps Coming Back

    A folder that refills after you empty it needs a closer look. This section lists things to check. We did not reproduce any of them, so treat them as places to look rather than diagnoses.

    Check what keeps writing into the folder

    Look at the folder again just before you retry. If it already holds files, something wrote them in the meantime. Possibilities include an FTP client that is syncing a local copy, a backup restore, or a plugin that creates its own data folder. The date and time on the files in File Manager show when they appeared.

    Rule out space and permissions first

    This error is not a disk or permission error. Those show other messages. If you see Could not create directory read our guide to that error, and if the account is near its file limit read the inode limit guide. If WordPress asks for connection details instead, the FTP credentials guide explains why.

    What the Destination Folder Already Exists Lab Did Not Test

    Four limits apply to everything above. First, the lab ran on one workstation with a direct filesystem, so FTP and SSH filesystem methods were not tested. Second, Install Now from the theme directory screen was not run, only a theme zip upload. Third, we did not test multisite, an interrupted install, a timeout partway through unpacking, or WP-CLI. Fourth, we read the cPanel documentation for the hidden files setting but did not click through File Manager.

    We also make no claim about how any AHosting server is configured. The behavior described is WordPress core behavior on version 7.1.4.

    Still Seeing Destination Folder Already Exists? Send the Exact Message

    Once the folder is clear and the plugin installs, you are done. If the error keeps returning, the useful next step is a look at the account itself. AHosting runs web hosting and reseller hosting accounts on cPanel, and the steps in this guide are the same on both.

    Open a ticket with the exact line including the full folder path, whether you used Install Now or a zip, and what the folder holds with hidden files shown. We will look at it with you.

    Frequently Asked Questions: Destination Folder Already Exists

    What does the destination folder already exists error mean in WordPress in 2026?

    Specifically, it means WordPress unpacked your plugin or theme, found a folder with the same name already on disk, saw that the folder was not empty, and stopped. In WordPress 7.1.4 that decision sits in wp-admin/includes/class-wp-upgrader.php, lines 699 to 707. Nothing is overwritten, and the folder is left as it was.

    Why does WordPress say destination folder already exists when the plugin is not installed?

    In other words, the folder is on disk but WordPress does not list a plugin in it. In our lab a folder with one loose file, one hidden .htaccess file or one empty subfolder all stopped the install. A leftover from an earlier attempt, an FTP upload or a restore is a common way to get there.

    Can I delete the folder safely when destination folder already exists appears in 2026?

    Typically yes, after you look inside it. Check the full path in the message, show hidden files, and move anything you want to keep to a folder outside wp-content. Then delete the leftover and run the install again. If a working copy is listed under Installed Plugins, update or delete it from the Plugins screen instead.

    Does an empty folder cause the destination folder already exists error?

    Indeed it does not. In our WordPress 7.1.4 lab an empty plugin folder installed normally. The check reads the folder contents and only stops when the result is not empty, so the folder you are looking at may be a different one from the path in the message, or it may hold hidden files that your file manager is not showing.

    Replace current with uploaded vs deleting the folder: which fixes destination folder already exists?

    However, they do different things. Replace current with uploaded appears only for a zip upload of a plugin that WordPress already lists, and in our lab it removed every file in the old folder before installing. Deleting the folder by hand gives the same clean result for any case, including leftovers WordPress does not recognize. Back up either way.

    Install Now vs zip upload: which shows the destination folder already exists error differently in 2026?

    Notably, the zip upload adds a screen. When WordPress finds a valid plugin in the folder it shows This plugin is already installed, a comparison table and a Replace current with uploaded button. Install Now from the plugin directory shows the plain error and the words Plugin installation failed. Both use the same underlying check.

    How do I find hidden files that cause destination folder already exists in cPanel File Manager?

    Specifically, open File Manager, choose Settings, and select Show Hidden Files (dotfiles), as the cPanel documentation describes. Then open the folder named in the error message. A file such as .htaccess counts as content for WordPress even though File Manager hides it by default, so the folder looked empty until you changed that setting.

    Can AHosting support look at it when destination folder already exists keeps coming back?

    In practice, open a ticket. Include the exact message with the full folder path, whether you used Install Now or a zip upload, and what the folder holds with hidden files shown. We will look at it with you. A folder that refills after you empty it needs a closer look than a one-off leftover.

    What should I send AHosting in 2026 when a plugin install fails with this folder error?

    Overall, four things: the exact line including the path, the name and version of the plugin or theme, the method you used, and the time of the attempt. That lets us tell a leftover folder, a permission problem and a disk limit apart without guessing. Please do not send a password in the ticket.

    Is destination folder already exists a WordPress problem or an AHosting server problem?

    Overall, it is mostly a WordPress result. The check is in WordPress core and it reports what it found in the folder. As a result, a disk limit or a permission problem shows a different message, such as Could not create directory. We cannot say from the message alone how a given account got the leftover, so ask us if it repeats.

    October 29, 2026
  • Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Checks and How to Fix It

    Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Checks and How to Fix It

    • Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Is Telling You
    • Why the File Type Is Not Permitted Message Reads Two Ways
    • The Three Checks
    • Files Where the File Type Is Not Permitted by Default
    • When the File Type Is Not Permitted Because the Content Does Not Match
    • Who Can Skip the Check: Administrators Are Not Exempt
    • Fixing the Error for One Type with upload_mimes
    • Why ALLOW_UNFILTERED_UPLOADS Is the Wrong Fix
    • When a Server Is the Cause: What the fileinfo Extension Changes
    • The File Type Is Not Permitted Decoder Table
    • Try the File Type Finder
    • What Can AHosting Do?
    • Frequently Asked Questions: File Type Is Not Permitted
      • Why does WordPress keep saying the file type is not permitted in 2026?
      • How do I fix the file type is not permitted error for SVG files in WordPress 2026?
      • Is the file type is not permitted message vs not allowed to upload this file type the same error?
      • Why is the file type is not permitted even when I am logged in as an administrator?
      • Is ALLOW_UNFILTERED_UPLOADS vs the upload_mimes filter the safer fix when the file type is not permitted?
      • Why does WordPress say the file type is not permitted for a text file I renamed to .jpg?
      • Can AHosting support tell me why the file type is not permitted on my WordPress upload?
      • Should I ask AHosting to change a server setting when the file type is not permitted?
      • Will the file type is not permitted error go away after I update WordPress in 2026?
      • On AHosting WordPress hosting, is zipping a blocked file better vs converting it when the file type is not permitted?
    TL;DR

    WordPress refuses an upload when the extension is not on its allowed list, when the real content of the file does not match the extension, or when neither check passes and your account lacks the unfiltered upload capability. SVG, JSON and font files fail the first check on a default install. In a WordPress 7.1.4 lab, an administrator was refused all three, a text file renamed to .jpg was refused, and one upload_mimes filter let the first three types through.

    Listen: a WordPress upload is refused when the extension is not listed, the real content does not match, or the account cannot skip both checks. By Matt Chrust, Director of Business Development, AHosting.

    Sorry, This File Type Is Not Permitted for Security Reasons: What WordPress Is Telling You

    You pick a file in the Media Library and WordPress answers that the file type is not permitted for security reasons. The text comes from the WordPress upload code itself: WordPress ran a short list of checks on the upload, and your file failed one of them. This guide walks through the three checks, shows which files fail them on a default install, and gives the smallest safe fix for each case.

    We tested every claim here on a real WordPress 7.1.4 install with PHP 8.5.10 and read the matching lines of core code. It was a workstation lab, not an AHosting server, so where a result depends on server software we say so.

    Short version: the message names the file type, but the file type is only the symptom. Three different problems produce the same sentence, and each has a different fix, so the first job is to tell them apart.

    Why the File Type Is Not Permitted Message Reads Two Ways

    Search results mix two sentences, and they come from different WordPress releases. Reading the upload code for each release, we found the old sentence, “Sorry, this file type is not permitted for security reasons.”, in version 4.9 and in version 5.2, at wp-admin/includes/file.php in the 5.2 tag. In the 5.9 tag, and in every tag we checked up to 7.0, the same place prints “Sorry, you are not allowed to upload this file type.” We checked tags rather than release notes, so we cannot name the exact release that changed the wording.

    The conditions around the sentence did not change in a way that matters to you. On current WordPress the line is wp-admin/includes/file.php line 972, and it fires when the type or the extension came back empty and your account lacks one capability. Older sites, plugins that print their own text and forum posts still use the first sentence, which is why it keeps its search volume.

    Two neighbors look similar but are different faults. An empty file produces a separate message about the file being empty. A server that cannot store the upload gives the different errors in our guides to the missing temporary folder error and the 413 request entity too large error. A similar-sounding permissions message, covered in our guide to the not allowed to access this page error, is a different fault. If your message is neither of the two sentences above, you are on the wrong page.

    The Three Checks

    Every upload through the Media Library passes through one function, wp_check_filetype_and_ext(), which the WordPress developer reference describes. It runs the file through three checks in a fixed order.

    1. The extension. WordPress matches the end of the file name against its allowed list. The matching code, wp_check_filetype(), looks only at the name. If nothing matches, there is no type.
    2. The real content. If the PHP fileinfo extension is loaded, WordPress asks it what the file actually contains. When that answer differs from the type the extension claims, WordPress treats the file as dangerous and discards the type (functions.php lines 3207 to 3209 and 3310 to 3318).
    3. The capability. Back in the upload handler, if the type or extension is still empty, the error appears unless your account holds unfiltered_upload (file.php lines 971 and 972).

    That order explains most confusion. The third check is the only one that names your account, and on a default install nobody passes it. So the extension and the content decide the result for everyone, administrators included.

    The three checks behind a file type is not permitted error An upload passes three checks in order. First, the file extension must appear in the allowed list built by get_allowed_mime_types. Second, the real content, read by the PHP fileinfo extension, must match the type that the extension claims. Third, if either check left no type, only a user holding the unfiltered upload capability may continue; everyone else sees the error. In the lab, administrators did not hold that capability until a constant was set. Three checks, and one capability that can skip them Lab: WordPress 7.1.4, PHP 8.5.10, 2026-10-28 1. The extension Is .svg, .json or .woff2 on the allowed list? Default list: no 2. The real content Does fileinfo read the same type the extension claims? Text named .jpg: no 3. The capability Did a check fail and does the user lack unfiltered upload? Then the error appears Fixes map to the checks: add one type to the allowed list, save a real file in the right format, or (rarely, and with care) grant the capability that skips both Sources: wp-admin/includes/file.php and wp-includes/functions.php in WordPress 7.1.4

    Notice that the type your browser sends plays no part. In the lab we sent an SVG as application/octet-stream and WordPress decided from the name and the content alone, and a browser MIME sniffing standard describes the same idea from the browser side, weighing a supplied type against what the content shows. Changing the type in a plugin or a script therefore cannot help.

    Files Where the File Type Is Not Permitted by Default

    The allowed list is built by get_allowed_mime_types() from a table in wp_get_mime_types(). We read that table in WordPress 7.1.4. It has entries for JPEG, PNG, GIF, WebP, AVIF, HEIC, PDF, ZIP, CSV, text and common office files. It has no entry for SVG, JSON, WOFF, WOFF2, TTF or OTF. The function also removes SWF and EXE for everyone, and removes HTML and JS for any account without the unfiltered_html capability.

    The table shows what we saw when we uploaded each file as an administrator on a single site through the same endpoint the Media Library uses.

    FileReal type foundResult on a default install
    logo.svgimage/svg+xmlRefused, extension not on the list
    data.jsonapplication/jsonRefused, extension not on the list
    font.woff2font/woff2Refused, extension not on the list
    shell.phptext/x-phpRefused, PHP is not on the list
    script.js with one wordtext/plainRefused, the content was read as plain text
    notes.txt and data.csvtext/plainAccepted
    real PNG, JPEG and HEIC imagesimage/png, image/jpeg, image/heicAccepted
    empty.txtapplication/x-emptyDifferent message, the file is empty
    AHosting WordPress Upload Check Lab Results: what an administrator could upload on a default WordPress 7.1.4 install, lab run 2026-10-28. Not an AHosting server.

    Read the first four rows as the answer to most searches. The content check found the correct real type for SVG, JSON and WOFF2, and they were still refused. Nothing is wrong with those files. Their extensions are simply not listed, so the fix is on the list rather than on the file.

    When the File Type Is Not Permitted Because the Content Does Not Match

    The second check catches files whose name and content disagree. We made two such files. A plain text file named fake.jpg was refused, and so was a text file named doc.pdf. In both cases fileinfo reported plain text while the extension claimed an image or a PDF.

    Real images with the wrong extension behaved differently, and the reason is a nice detail. For image types, WordPress runs a separate correction first. A PNG named real-as.jpg was accepted and stored with a corrected .png name, and a JPEG named real-as.png was stored as .jpg. The correction lives in the image branch of wp_check_filetype_and_ext() and sets a replacement file name. Anything that is not an image goes to the strict comparison instead.

    So a refusal of a “photo” almost always means the file is not what its name says. Export from a graphics app, a camera or a phone often leaves a file with an extension the content does not back up, for example a text error page saved as an image by a download tool. Open the file in an editor, confirm it shows a picture, then save a fresh copy as JPEG or PNG. Our plain guide to the server cannot process the image error covers the next problem you may meet after a file passes this check.

    If WordPress still refuses a file you know is a real image, send us the file name and the exact sentence. We can check how fileinfo reads it on your account, which is something a dashboard cannot show you.

    Who Can Skip the Check: Administrators Are Not Exempt

    It is easy to assume that administrators bypass upload restrictions. In the lab that was false. As a single-site administrator we were refused SVG, JSON, WOFF2, PHP and a one-word JS file. The administrator role does hold the unfiltered_upload capability, set in schema.php lines 891 to 895. The capability does not work on its own, though. capabilities.php lines 587 to 593 turn it into do_not_allow unless a constant named ALLOW_UNFILTERED_UPLOADS is defined as true, and on a multisite network only a super administrator gets it even then.

    The practical meaning is simple. On a default install the account type changes nothing. Whether you are an administrator, an editor or an author, the extension list and the content check decide. Logging in with a stronger account, or asking a client for one, is not a fix.

    Fixing the Error for One Type with upload_mimes

    When the extension is the problem, add that single type to the allowed list. WordPress built this hook for the purpose. A comment above the check in file.php line 959 says to override the list or use the upload_mimes filter, and the filter documentation describes the same hook. Put the code in a small plugin or a must-use plugin, not in a theme file you might switch later.

    add_filter( 'upload_mimes', function ( $mimes ) {
    	$mimes['svg'] = 'image/svg+xml';
    	return $mimes;
    } );

    In the lab we added SVG, JSON and WOFF2 this way. All three uploaded after the filter was active, and each was stored under its own name. The same filter left fake.jpg and shell.php refused, because it changes only the extension list and the content check still ran. That is the behavior you want from a fix.

    Keep two cautions in mind. An SVG is a text document that can contain script, so allow it only for accounts you trust, and consider a plugin that cleans SVG files if visitors can upload. A font file will be served by your site, so confirm you hold the license. If a standard format exists, converting the file is simpler than changing the list.

    Why ALLOW_UNFILTERED_UPLOADS Is the Wrong Fix

    The other popular answer is to add define( 'ALLOW_UNFILTERED_UPLOADS', true ); to wp-config.php. It works, and that is the problem. With the constant set, every upload we tried succeeded, including the SVG, the JSON file, a JS file, a PHP file, a text file named as a JPEG and a text file named as a PDF. The constant does not add a type. It switches the check off for everyone who holds the capability.

    We did not request the PHP file after uploading it, so we cannot say whether a server would run it. Whether it runs depends on server configuration that differs between hosts. The point stands without that test: an upload form that accepts a file because it is allowed to accept anything is a much larger opening than the one type you needed.

    One practical note from the run. The first upload attempt, made seconds after we edited wp-config.php, still failed, and the same files succeeded a few seconds later. We read that as the old configuration still being served from cache. If you add the constant, allow a moment before testing, and remove it once you are done.

    When a Server Is the Cause: What the fileinfo Extension Changes

    The content check runs only when the fileinfo extension is loaded. In functions.php line 3207 the condition reads extension_loaded( 'fileinfo' ). Without it, WordPress skips the real-content comparison and decides from the extension alone. We did not test that case, because fileinfo is part of our lab PHP, and we do not claim what any hosting server has.

    What you can check yourself is where the message comes from. It is produced by WordPress PHP code, so the request already reached WordPress. If a web firewall stopped the upload earlier, you would see a different response from the server, not either WordPress sentence. We did not test a firewall, so treat that as something to read in your own logs.

    Server software can still matter through the file you send. A tool in your workflow may change how it writes a file, and fileinfo then reads the new bytes. If the same file uploads on one site and not on another, compare the real file, not the name. The file command project explains the idea behind content detection: it looks at what a file contains instead of relying on the extension.

    The File Type Is Not Permitted Decoder Table

    Use this table with the file and the message in front of you. Match the symptom, then run the first check. The last column records what we saw in the lab.

    SymptomLikely causeFirst checkLab result
    SVG, JSON or font refusedExtension not on the listIs the type in the upload_mimes filter?Accepted after the filter
    A photo refusedContent does not match the nameDoes the file open as an image on your computer?Text named .jpg refused
    A real image stored with a different extensionNone, WordPress corrected the nameCheck the stored file namePNG named .jpg stored as .png
    PHP, JS or HTML refusedNot allowed or needs unfiltered HTMLUse FTP or a plugin for code, not MediaPHP and JS refused
    Works for you, fails for a clientAccount difference only for HTML and JSCompare roles for the unfiltered HTML capabilityAdmin not exempt for the rest
    Everything accepted, even odd filesALLOW_UNFILTERED_UPLOADS is onSearch wp-config.php for the constantAll seven test files accepted
    Message about an empty fileZero bytes arrivedFile size, then PHP upload limitsDifferent message
    Match the message and the file to the cause. WordPress 7.1.4, PHP 8.5.10, lab run 2026-10-28.

    Try the File Type Finder

    Pick the kind of file and the account you used. The tool names the likely cause and jumps to the section that fixes it.

    Find Why Your File Type Is Not Permitted

    Answer the questions above and the likely cause appears here.
    Read the matching section

    What Can AHosting Do?

    Once you know which check failed, the fix is one filter, one converted file or one removed constant. The part you cannot see from the dashboard is how fileinfo reads your file and whether something on the account changes the request. If a plain JPEG is refused, or the message is neither sentence above, open a ticket with the exact text, the file name and the page where you uploaded it, and we will look at it with you.

    The shared plans on our web hosting page include a cPanel File Manager and FTP access, which is the right route for code files that do not belong in the Media Library. The WordPress hosting plans are the page to compare if you want the upload and file work handled on a WordPress-focused account. If you meet this after every client launch, see the reseller hosting plans.

    Frequently Asked Questions: File Type Is Not Permitted

    Why does WordPress keep saying the file type is not permitted in 2026?

    Specifically, WordPress compared your file with its list of allowed types and found no match. The comparison looks at the extension, at the real content of the file and at your user capabilities. SVG, JSON and font files fail the first check on every default install.

    How do I fix the file type is not permitted error for SVG files in WordPress 2026?

    In practice, add the SVG type to the upload_mimes filter in a small plugin, then upload again. In our lab on WordPress 7.1.4 that one filter let SVG, JSON and WOFF2 files through. Remember that an SVG is a text document that can carry script, so allow it only for people you trust.

    Is the file type is not permitted message vs not allowed to upload this file type the same error?

    Indeed, they are the same check with different wording. WordPress 5.2 printed the first sentence and WordPress 5.9 and later print the second at the same place in the upload code. The cause and the fixes are identical, so use whichever text you see.

    Why is the file type is not permitted even when I am logged in as an administrator?

    Typically, the administrator role does not skip the check on a default install. The skip needs the unfiltered upload capability, and WordPress grants it only when a constant in wp-config.php switches it on. In our lab an administrator was refused SVG, JSON, PHP and font files.

    Is ALLOW_UNFILTERED_UPLOADS vs the upload_mimes filter the safer fix when the file type is not permitted?

    Overall, the filter is the safer fix. It opens one named type and every other check still runs. The constant removes the check for every user who holds the capability, and in our lab it accepted a text file named as a JPEG and a PHP file.

    Why does WordPress say the file type is not permitted for a text file I renamed to .jpg?

    In fact, WordPress reads the file content as well as its name. The content check reported plain text, which does not match the JPEG type that the extension claims, so the upload was refused. Save a real image in the format you need rather than renaming one.

    Can AHosting support tell me why the file type is not permitted on my WordPress upload?

    Specifically, open a ticket with the exact message, the file name and extension, and what happened when you tried a small real image. That tells us whether this is the allowed-type list, a content mismatch or something on the server, so the first reply can be specific.

    Should I ask AHosting to change a server setting when the file type is not permitted?

    Typically, no. In our lab the message came from WordPress core code, which ships with WordPress itself. Ask us only if a plain JPEG is refused, if the message differs from the two WordPress sentences, or if a security rule blocks the request before WordPress runs.

    Will the file type is not permitted error go away after I update WordPress in 2026?

    Overall, an update will not add SVG, JSON or font types to the allowed list. WordPress 7.1.4 still has no entry for them, and the message wording only changed between the 5.2 and 5.9 releases. Keep the site current, then handle the type with the filter.

    On AHosting WordPress hosting, is zipping a blocked file better vs converting it when the file type is not permitted?

    Ultimately, converting is the cleaner choice when a standard format exists, such as a PNG or JPEG. WordPress lists ZIP as an allowed type in its source, and we did not upload a ZIP in our lab. A zip hides the file inside a download, so readers cannot see it on the page.

    October 28, 2026
  • Failed to Open Stream in WordPress: What the Message Is Really Telling You

    Failed to Open Stream in WordPress: What the Message Is Really Telling You

    • Failed to Open Stream in WordPress: Read the Message Before You Touch a File
    • What a Failed to Open Stream Message Contains
    • Include or Require: Why the Same Failed to Open Stream Can Stop Your Site
    • Failed to Open Stream: No Such File or Directory
    • Failed to Open Stream: Permission Denied
    • Failed to Open Stream: HTTP Request Failed
    • When open_basedir Turns a Failed to Open Stream into a Fatal Error
    • Why a Failed to Open Stream Message Can Be Invisible
    • What a Failed to Open Stream Looks Like Under Each Debug Setting
    • The Failed to Open Stream Decoder Table
    • Try the Failed to Open Stream Finder
    • What AHosting Can Do About a Failed to Open Stream Error
    • Frequently Asked Questions: Failed to Open Stream
      • What does the failed to open stream error mean in WordPress in 2026?
      • Why is my WordPress site not opening after a failed to open stream message?
      • How do I fix failed to open stream: no such file or directory in WordPress 2026?
      • How do I fix failed to open stream: permission denied on AHosting shared hosting?
      • Is a failed to open stream warning vs a Failed opening required fatal error a different problem?
      • Does failed to open stream: HTTP request failed mean my WordPress site is hacked in 2026?
      • Can WP_DEBUG_LOG vs display errors show me a failed to open stream message safely?
      • Will AHosting support look at a failed to open stream error on my WordPress site?
      • Why does a failed to open stream error appear after I move my WordPress site to AHosting in 2026?
      • Should I set a folder to 777 to stop a failed to open stream permission denied error?
    TL;DR

    A failed to open stream message in WordPress is PHP reporting that it could not open a file or a web address. The words after the colon name the cause: no such file or directory, permission denied, HTTP request failed, or an open_basedir block. Read those words and the path before them, then fix that one thing. In a WordPress 7.1.3 lab, a missing include was only a warning, a missing required file was a fatal error, and with display switched off a visitor saw either nothing or a blank page.

    Listen: the words after the colon in a failed to open stream warning name the cause, and the function at the start says whether the site stops. By Matt Chrust, Director of Business Development, AHosting.

    Failed to Open Stream in WordPress: Read the Message Before You Touch a File

    A failed to open stream warning looks like a wall of server paths, and most guides answer it with the same checklist: reinstall WordPress, reset permissions, disable every plugin. That order wastes time, because the message already says what failed. It names the file PHP wanted, gives a reason in plain words, and points at the plugin or theme file that asked for it.

    We checked this on 2026-10-27 in a WordPress 7.1.3 lab running PHP 8.5.10, with a small test plugin that included, required and fetched things that were missing, locked or blocked. Every cause printed a different reason after the colon, and every reason had a different fix. A missing include was a warning and the page kept loading. A missing required file was a fatal error. With display switched off the same fault produced a blank page, or nothing at all.

    This guide shows how to read the message, what each reason means, and why you sometimes never see it. It ends with a decoder table and a short finder. If your message ends differently from the ones covered here, the structure still applies, so start with the reason.

    What a Failed to Open Stream Message Contains

    A stream is PHP’s word for anything it can read from or write to: a file on disk, or a web address opened with a function such as file_get_contents. When the open call fails, PHP raises a warning with the same sentence every time. Our lab printed Failed to open stream with a capital F, while search results show both spellings, so search for either.

    The message has four parts, and only the third names the cause. The function and the target come first, for example include( followed by a path. Next is the fixed phrase. Third is the reason, which comes from the operating system or from the URL handler. Last is the file and line that made the call, which tells you which plugin or theme to blame. Figure 1 splits one message into those parts.

    The four parts of a failed to open stream message A PHP warning reads include(path): Failed to open stream: reason in file on line number. The first part names the function and the file it tried to open. The second part is the same fixed phrase every time. The third part is the reason, which names the cause, such as no such file or directory or permission denied. The fourth part names the plugin or theme file and the line that made the call. Only one of the four parts names the cause Lab: WordPress 7.1.3, PHP 8.5.10, 2026-10-27 1. Call and target include(PATH) 2. Fixed phrase Failed to open stream: 3. The reason No such file or directory 4. Who called it in FILE on line N which file PHP wanted to open identical for every cause, so skip it the operating system or the stream wrapper says why the plugin or theme to blame or to disable Reasons seen in the lab: No such file or directory, Permission denied, HTTP request failed, no suitable wrapper, Operation not permitted Sources: PHP 8.5.10 output in a WordPress 7.1.3 lab

    One more line often follows. For an include, PHP adds a second warning, Failed opening followed by the path and the words “for inclusion”. It carries no new information, so you can ignore it. What changes the outcome is the function in part one, which the next section covers.

    Include or Require: Why the Same Failed to Open Stream Can Stop Your Site

    The PHP manual page for include explains that include raises a warning when it cannot find a file and carries on, while require treats the same fault as fatal. We saw exactly that. With the file nope.php missing, an include returned HTTP 200 with two warnings above the page content. A require on the same missing file returned HTTP 500 with the warning, an uncaught fatal error reading Failed opening required, and WordPress’s own critical error notice.

    That difference explains most “my site is down” reports. A theme that includes an optional template part fails softly, and the owner sees a stray line of text. A plugin that requires its main class file fails hard, and the whole request ends. The word at the start of the message tells you which one you have before you open a single file.

    Core files are the harshest case. We removed wp-includes/class-wp-hook.php from the lab install and switched display off. The result was an HTTP 500 with an empty body, zero bytes, and a fatal error in the log pointing at wp-includes/plugin.php line 25. A visitor sees a blank screen. Our guide to the WordPress white screen of death covers the wider list of causes behind that screen.

    Failed to Open Stream: No Such File or Directory

    This reason is the most common, and it is a literal statement: nothing exists at that path. The open system call documentation defines the error as a component of the path that must exist but does not. PHP prints the operating system’s own words.

    Four situations produce it. A plugin or theme folder was deleted or only partly uploaded, so a file it includes is gone. Or a core update was interrupted, so a file under wp-includes is missing. After a move, a plugin may have stored an absolute path that names the old account, such as a home folder that no longer exists. Finally, a path may have the wrong case, which matters on Linux servers even though a laptop may forgive it.

    One result in the lab surprised us. We listed a plugin as active in the database and deleted its folder. WordPress threw no error at all and left the database entry in place on a front-end load. The reason is in wp-includes/load.php at line 1031: it adds a plugin to the load list only when file_exists() is true for the main file. So a missing main plugin file is skipped silently, and the message you see comes from a file the plugin includes later, not from the plugin itself.

    The fix follows the path. Confirm in File Manager or by SFTP that the exact path exists. Reinstall the plugin or theme if its folder is incomplete. Upload a fresh copy of the same WordPress version if a core file is missing. If an old absolute path is the cause, search the files for the old account name and replace it. Our guide to migrating WordPress to a new host covers moves that go wrong.

    Failed to Open Stream: Permission Denied

    Here the file exists, but the account PHP runs as may not open it. The NetBSD documentation for open lists two triggers: the permissions on the file itself deny the requested access, or search permission is denied on a folder in the path. The second one is easy to miss, because the file can look perfect while a folder above it blocks the way.

    We reproduced both in the lab. An included file set to mode 000 printed Failed to open stream: Permission denied. A path inside a folder set to mode 000 printed the same words, before PHP could even tell whether the file was there. So when you check permissions, check every folder from the site root down to the file, not only the file.

    On our shared servers PHP runs as your own cPanel account, so a correctly owned install is readable by the code that needs it. On sh193 we counted 530 document roots on 2026-10-01 and found exactly two files not owned by their account, both uploaded by hand as root. That count is one server and one day, but it points the right way: the usual cause is an odd owner or a stripped mode on one file or folder, not a general fault.

    Look at the owner and the mode of the named file and of each folder above it. If a file belongs to another user, ownership has to change, and that is a ticket rather than a setting. Do not widen permissions for everyone to make the message go away. If the same warning appears while WordPress is installing something, our guide to the could not create directory error covers the write side, and WordPress asking for FTP credentials covers ownership mismatches.

    Failed to Open Stream: HTTP Request Failed

    When the target in part one starts with https, no file on your disk is involved. A plugin asked a remote address for data, and the open call failed. The reason is then not an operating system message but the remote answer. In the lab, a request to a page that does not exist printed HTTP request failed! HTTP/1.1 404 Not Found. The status code after HTTP/1.1 is the remote server’s reply, so a 403 means it refused, and a 404 means the address is wrong.

    Two other reasons belong here. If the server disables URL access, PHP prints a line saying the https wrapper is disabled by allow_url_fopen=0, followed by Failed to open stream: no suitable wrapper could be found. If the host name cannot be resolved, the reason is a php_network_getaddresses failure. We reproduced all three.

    None of these is fixed by touching your own files. A 403 or 404 means the plugin is calling a broken or blocked address, so update the plugin or contact its author. If the wrapper is disabled, the plugin needs a setting that its host controls. A resolution failure points at DNS or at a network block on the server. Plugins that call remote services print this message whenever the service is down or has moved.

    When open_basedir Turns a Failed to Open Stream into a Fatal Error

    The open_basedir directive limits the folders PHP may open files from. When a path falls outside the list, PHP prints a line beginning open_basedir restriction in effect, then Failed to open stream: Operation not permitted. The first line names the path and lists the allowed folders, so the message gives you everything you need.

    We tested two cases. Opening /etc/hosts from the test plugin with the limit set to the WordPress folder printed both lines and returned an ordinary warning. Then we set the limit to a plugin subfolder only, which excludes the site root. The request failed before WordPress loaded, with a fatal error reading Failed opening required for index.php, and the location printed as Unknown on line 0. In our test, that is what a base directory that excludes the site root looked like.

    We did not measure what the limit is on an AHosting account, so we state nothing about our setting here. If your message contains the restriction line, the fix is to bring the path inside the allowed folders or to remove the code that reaches outside them. Where the directive is set depends on your host, so ask support for the value before changing anything.

    Why a Failed to Open Stream Message Can Be Invisible

    Many site owners never see the message at all, which is why the symptom is often just a blank page or a notice. The display depends on settings. In our lab, with debugging on and display on, the warnings were printed above the page. With WP_DEBUG off and PHP display off, the same include produced no visible output, and the warnings existed only in the PHP error log.

    For a require, the visitor saw WordPress’s generic notice instead of the message. The fatal error handler in wp-includes/class-wp-fatal-error-handler.php chooses its wording at lines 188 to 200: “There has been a critical error on this website” in the plainest case, with longer wording that mentions the admin email on protected screens such as wp-admin. The path itself stays in the log.

    To read it safely, follow the WordPress debugging guide: set WP_DEBUG and WP_DEBUG_LOG to true and WP_DEBUG_DISPLAY to false in wp-config.php. WordPress then writes the message to wp-content/debug.log and shows visitors nothing. We confirmed the log path in load.php at line 623. Reload the failing page, open the log and copy the newest failed to open stream line. Remove the constants when you are done, because the log can grow and expose paths.

    What a Failed to Open Stream Looks Like Under Each Debug Setting

    The table compares the same fault under two settings. If your problem is a different PHP complaint about output, our guide to headers already sent decodes that one in the same way.

    SettingMissing includeMissing requireMissing core file
    Debug and display onHTTP 200, two warnings printed above the pageHTTP 500, warning and fatal error printed, then the critical error noticeNot tested
    Debug off, display off, log onHTTP 200, nothing visible, warnings in the logHTTP 500, generic critical error notice, fatal error in the logHTTP 500, empty page of 0 bytes, fatal error in the log
    What a visitor sees for the same fault under two settings. WordPress 7.1.3, PHP 8.5.10, lab run 2026-10-27.

    The Failed to Open Stream Decoder Table

    Use this table with the message in front of you. Match the words after the colon, then run the first check. The last column records what we actually saw in the lab, so you can compare your own output.

    Reason after the colonWhat it meansFirst checkLab result
    No such file or directoryNothing exists at that pathDoes the exact path exist? Was the folder deleted or the site moved?Include: warning, page loads. Require: fatal error
    Permission deniedThe file or a folder above it blocks this accountOwner and mode of the file and of every folder above itMode 000 on the file, and on a folder in the path, both printed it
    HTTP request failed! HTTP/1.1 404A remote address answered with an errorWhich address, and which plugin calls it?Warning only, page loads
    no suitable wrapper could be foundThe server disables URL access (allow_url_fopen)Which plugin needs remote access?Printed after a line about the disabled https wrapper
    php_network_getaddresses failedThe host name did not resolveSpelling of the address, DNS from the serverWarning only, page loads
    Operation not permittedThe path is outside open_basedirThe allowed folder list in the preceding lineWarning, or fatal error at “Unknown on line 0” if the site root is excluded
    The Failed to Open Stream Decoder Table. Lab: WordPress 7.1.3, PHP 8.5.10, 2026-10-27, one workstation, not an AHosting server.

    Try the Failed to Open Stream Finder

    Pick the words from your message and what the page does. The tool names the likely cause and jumps to the section that fixes it.

    Find Your Failed to Open Stream Cause in Two Questions

    Answer the questions above and the likely cause appears here.
    Read the matching section

    What AHosting Can Do About a Failed to Open Stream Error

    Once you have the reason, the fix is usually one file or one folder. The part you cannot see from a dashboard is who owns the file and which path the code actually tried to open. If the message names a file you did not create, or a permission fault you cannot clear, open a ticket with the full message, the time it appeared and the page that triggered it, and we will look at it with you.

    The shared plans on our web hosting page include a cPanel File Manager where you can check owners and modes yourself. The WordPress hosting plans are the page to compare if you want the debugging and file work handled on a WordPress-focused account. If you manage several client sites and meet this after every migration, see the reseller hosting plans.

    Frequently Asked Questions: Failed to Open Stream

    What does the failed to open stream error mean in WordPress in 2026?

    Specifically, it means PHP tried to open a file or a web address and the attempt failed. The words after the colon give the cause, such as no such file or directory, permission denied or HTTP request failed. WordPress only passes along what PHP reports.

    Why is my WordPress site not opening after a failed to open stream message?

    In practice, it depends on the function named at the start of the message. A failed include is a warning and the page keeps loading. A failed require is a fatal error, so the page stops and WordPress shows its critical error notice or, with display switched off, nothing at all.

    How do I fix failed to open stream: no such file or directory in WordPress 2026?

    In practice, read the path in the message and check whether that exact file exists on the server. If a plugin or theme folder was deleted, reinstall it. If a core file under wp-includes is missing, upload a fresh copy of the same WordPress version. A hardcoded path from an old host needs editing.

    How do I fix failed to open stream: permission denied on AHosting shared hosting?

    Typically, the file or one of its parent folders is owned by another user or has its permissions stripped. On our shared servers PHP runs as your own cPanel account, so check the owner and the mode of the file and of every folder above it in File Manager. If the owner is not your account, open a ticket.

    Is a failed to open stream warning vs a Failed opening required fatal error a different problem?

    Similarly, both begin with the same failed to open stream line, so the cause is the same kind of fault. The difference is the function. Include continues after the warning, while require stops the request with a fatal error. Fix the missing or unreadable file and both disappear.

    Does failed to open stream: HTTP request failed mean my WordPress site is hacked in 2026?

    In fact, that message does not by itself mean a hack. It means a plugin asked a remote address for data and the remote server answered with an error such as 403 or 404, or the connection never completed. It points at the remote address, not at your files. Check the status code after HTTP/1.1 in the message.

    Can WP_DEBUG_LOG vs display errors show me a failed to open stream message safely?

    Overall, logging is the safer choice. With WP_DEBUG_LOG on and WP_DEBUG_DISPLAY off, WordPress writes the message to wp-content/debug.log and shows nothing to visitors. Display on a live site prints server paths on the page, so use it only briefly and switch it off again.

    Will AHosting support look at a failed to open stream error on my WordPress site?

    Specifically, open a ticket and paste the complete message, including the path and the words after the colon, together with the time it appeared. Those words tell us whether the cause is a missing file, an ownership fault or a blocked address, so the first reply can be specific.

    Why does a failed to open stream error appear after I move my WordPress site to AHosting in 2026?

    Typically, a plugin or theme stored an absolute server path from the old host, such as a home folder with the old account name. The path no longer exists, so PHP reports no such file or directory. Search the files for the old path and replace it with the new one.

    Should I set a folder to 777 to stop a failed to open stream permission denied error?

    Ultimately, opening a folder to every user hides the symptom and leaves the real fault, which is usually ownership, in place. Find which file or folder the message names, confirm your own account owns it, and restore ordinary permissions rather than granting access to everyone.

    October 27, 2026
  • 413 Request Entity Too Large in WordPress: Find the Layer That Said No

    413 Request Entity Too Large in WordPress: Find the Layer That Said No

    • 413 Request Entity Too Large in WordPress: Find the Layer That Said No
    • What a 413 Request Entity Too Large Error Actually Means
    • The Five Layers a 413 Request Entity Too Large Crosses
      • The 413 Layer Decoder Table
      • What the 413 Request Entity Too Large Table Does Not Claim
    • How to Tell Which Layer Returned the 413 Request Entity Too Large
      • Read the Server Header of the 413 Request Entity Too Large
      • What WordPress Prints When a 413 Request Entity Too Large Arrives
    • Which Layer Is Rejecting Your 413 Request Entity Too Large Upload?
    • What the Lab Measured About the 413 Request Entity Too Large Error
      • Why the 413 Request Entity Too Large Appeared Below the PHP Limit
      • What the Lab Did Not Cover
    • Fix the 413 Request Entity Too Large at the Layer That Answered
      • If nginx Returned the 413 Request Entity Too Large
      • If Apache Returned the 413 Request Entity Too Large
      • If Cloudflare Returned the 413 Request Entity Too Large
      • If PHP Returned the Message, It Was Not a 413 Request Entity Too Large
    • When a Bigger Limit Is the Wrong Fix for a 413 Request Entity Too Large
    • What AHosting Can Do About a 413 Request Entity Too Large
    • Frequently Asked Questions: 413 Request Entity Too Large
      • What does a 413 request entity too large error mean on WordPress in 2026?
      • Why does WordPress still show a 413 request entity too large error after I raise upload_max_filesize?
      • Nginx vs Apache vs Cloudflare: which one returns the 413 request entity too large error?
      • 413 request entity too large vs the link you followed has expired: how do I tell them apart in 2026?
      • How large can an upload be before Cloudflare returns a 413 request entity too large error on the Free plan in 2026?
      • What default limit makes nginx return a 413 request entity too large error for a WordPress upload?
      • Can I fix a 413 request entity too large error myself on AHosting shared hosting?
      • Does AHosting WordPress hosting include WP-CLI so I can add a large file past a 413 request entity too large error?
      • What should I send AHosting support when a 413 request entity too large error blocks my upload?
      • Why does the media uploader say the server cannot process the image when the real cause is a 413 request entity too large?
    TL;DR

    A 413 request entity too large error means a layer in front of WordPress refused the upload before PHP saw it, so raising upload_max_filesize cannot fix it. Five layers can say no: the browser uploader, a CDN, the web server, PHP and WordPress. Read the Server header of the failed request to find the one that answered, then change the limit there. In a WordPress 7.1.3 lab, nginx rejected a 1 MB file while the Media screen promised 100 MB.

    Listen: a 413 is sent by a layer in front of PHP, and the Server header of the failed request tells you which. By Matt Chrust, Director of Business Development, AHosting.

    413 Request Entity Too Large in WordPress: Find the Layer That Said No

    A 413 request entity too large error appears when you upload a file and the response is not a WordPress screen at all, just a short page with a status code. Most guides answer it with the same advice: raise upload_max_filesize and try again. A forum thread in the search results describes exactly that: a site set to 500 MB that still fails on a 15 MB file.

    The reason is where the 413 is generated. It comes from a layer that handles your request before PHP starts, so no PHP setting can change it. We tested this on a WordPress 7.1.3 install in a lab on 2026-10-26: PHP set to 100 MB, nginx in front with no extra setting, and a 1 MB file. The upload was rejected with a 413 while the Media screen still read “Maximum upload file size: 100 MB.”

    This guide shows the five layers an upload crosses, how to read which one answered, and where each limit is changed. It also covers what WordPress prints on its own, because that message often hides the real status. If your error reads “The link you followed has expired” instead, that is a different failure with a different fix, and we compare the two below.

    What a 413 Request Entity Too Large Error Actually Means

    A 413 is an HTTP status code. It says the server is refusing the request because the body, the part that carries your file, is larger than the server is willing to process. RFC 9110, section 15.5.14, now names it “Content Too Large”; nginx still prints the older phrase “Request Entity Too Large”, and Cloudflare’s documentation calls it “Payload Too Large”. All three describe the same status.

    Two things follow from that definition. First, the server decides on size, and it does so as soon as it reads the request headers or the first part of the body, long before WordPress loads. Second, a 413 is never produced by wp-admin code. In the WordPress 7.1.3 upload scripts no branch handles a 413 on its own, and the bundled uploader library only maps the number to its name, so a 413 lands in a generic error message.

    Compare that with the two PHP limits, which behave very differently. In our lab a file over upload_max_filesize got a polite WordPress notice, and a request over post_max_size got the expiry page with status 403. Neither was a 413. Our guide to the link you followed has expired message covers that half in detail, so this guide stays on the layers in front of PHP.

    The Five Layers a 413 Request Entity Too Large Crosses

    An upload is one long POST request. On its way from your browser to the folder on disk it passes five checkpoints, and each can refuse it with its own message. Only two of them can send a 413.

    Five layers an upload crosses before WordPress stores the file An upload starts in the browser uploader, which checks the size WordPress reports. It then crosses a CDN such as Cloudflare, which allows 100 MB on Free and Pro. Next is the web server: nginx defaults to 1 MB, and Apache has defaulted to 1 GiB since 2.4.54. Then PHP, which applies post_max_size and upload_max_filesize and never returns a 413. Last is WordPress, which stores the file. A 413 can only come from the CDN or the web server. A 413 comes from the first layers, not from PHP Lab: WordPress 7.1.3, nginx 1.31.6, PHP 8.5.10, 2026-10-26 1. Browser checks the size WordPress reports, before sending 2. CDN or proxy Cloudflare: 100 MB on Free and Pro 3. Web server nginx default 1 MB Apache 1 GiB since 2.4.54 4. PHP post_max_size and upload_max_filesize 5. WordPress stores the file Layers 2 and 3 return the 413 a plain page that names the server Layer 4 never returns a 413 a notice, or a 403 expiry page Sources: nginx.org, httpd.apache.org, Cloudflare support docs, lab measurements

    The 413 Layer Decoder Table

    The table below lists each layer with the status it returns, the default we could verify, and who can change it. It is the reference the rest of this guide uses.

    LayerWhat it returnsDefault we verifiedWho changes it
    1. Browser uploaderNo request is sent. Message: “[file] exceeds the maximum upload size for this site.”The value the Media screen shows, the smaller of the two PHP limitsYou, through the PHP limits
    2. CDN or proxyA 413 from the CDN; the Server header names itCloudflare: 100 MB on Free and Pro, 200 MB on Business, up to 5 GB on EnterpriseYou, in the CDN dashboard, within the plan
    3. Web serverA 413 page that names the servernginx: 1m. Apache: 1 GiB since 2.4.54, unlimited before. LiteSpeed: its own setting, not measured hereThe server owner; on shared hosting, the host
    4. PHPNo 413. A notice for the file limit, or a 403 expiry page for the body limitStock PHP: 2M file limit, 8M body limitYou, through the cPanel PHP editor or a user INI file
    5. WordPressStores the file, or reports its own errorReads the PHP values through wp_max_upload_size()Plugin or code filter
    The 413 Layer Decoder Table: five layers, what each returns, and who can change it.

    What the 413 Request Entity Too Large Table Does Not Claim

    Two caveats are worth stating. The nginx and Apache defaults come from their official documentation, and the nginx figure was also measured in the lab. We did not reproduce an Apache 413 in the lab, and we did not measure LiteSpeed, so the table gives no LiteSpeed number. Cloudflare’s figures come from its support page on error 413, dated by that page 2026-09-28.

    How to Tell Which Layer Returned the 413 Request Entity Too Large

    You do not need server access to find the layer. Open your browser developer tools, switch to the Network tab, repeat the upload, and click the failed request. It is usually the one named async-upload.php. The status column shows 413, and the response headers show who sent it.

    Read the Server Header of the 413 Request Entity Too Large

    The Server header names the software that answered. In our lab the nginx rejection carried Server: nginx/1.31.6 and a one-line page reading “413 Request Entity Too Large”. A response from behind Cloudflare carries server: cloudflare and a cf-ray header; we confirmed both on this site on 2026-10-26. If the header names Cloudflare, the request never reached your web server.

    Be careful with one case. A Cloudflare header proves Cloudflare is on the path, not that it was the one that refused. Even when a file under 100 MB fails with a Cloudflare header, the web server behind it may have been the one that refused, and the response body tells you which. Likewise, a page that names nginx or Apache came from the web server.

    What WordPress Prints When a 413 Request Entity Too Large Arrives

    The WordPress media uploader maps any HTTP status of 400 or higher to one generic error, and the wording depends on the file. In the 7.1.3 source, plupload.js treats a status at or above 400 as an HTTP error, and wp-plupload.js turns it into one of two sentences. See the two strings in script-loader.php for the exact text.

    • For a non-image file: “Unexpected response from the server. The file may have been uploaded successfully. Check in the Media Library or reload the page.”
    • For an image: “The server cannot process the image. This can happen if the server is busy or does not have enough resources to complete the task. Uploading a smaller image may help. Suggested maximum size is 2560 pixels.”

    The image sentence is the misleading one. It sends you off to resize pictures when the real status was a 413 about request size. We read this in the source and did not run the browser uploader in the lab, so treat the mapping as read from code, not observed on screen. The PHP-side causes of that same sentence are in our guide to the server cannot process the image error.

    Which Layer Is Rejecting Your 413 Request Entity Too Large Upload?

    Use the tool below if you already have the failed request open. It asks what you saw and what the Server header says, then points to the matching section.

    Find the Layer That Said No in Three Questions

    Answer the questions above and the likely layer appears here.
    Read the matching section

    What the Lab Measured About the 413 Request Entity Too Large Error

    The lab was one workstation, not an AHosting server. It ran WordPress 7.1.3 on the PHP 8.5.10 built-in server with SQLite, with nginx 1.31.6 as a reverse proxy. Each request logged in as an administrator, read the upload nonce from the Media screen, and posted a file of random bytes to async-upload.php with curl.

    SetupFileResult
    PHP file limit 2M, body limit 8M1 MBHTTP 200, file stored
    Same4 MBHTTP 200, notice: the file exceeds the upload_max_filesize directive
    Same10 MBHTTP 403, page: “The link you followed has expired.”
    PHP 100M and 100M, nginx with no setting1 MB and 2 MBHTTP 413 from nginx; Media screen still said 100 MB
    nginx limit raised to 64m2 MBHTTP 200, file stored
    nginx limit 64m70 MBHTTP 413 from nginx
    Lab results, WordPress 7.1.3 with nginx 1.31.6 and PHP 8.5.10, 2026-10-26.

    Why the 413 Request Entity Too Large Appeared Below the PHP Limit

    Rows four to six carry the finding. With PHP at 100 MB and nginx on its stock setting, a 1 MB file produced a request of 1,049,122 bytes, and the nginx log said the client “intended to send too large body”. The Media screen reported 100 MB the whole time, because it reads PHP, not nginx.

    The same finding explains how a real browser reaches a 413 at all. In the 7.1.3 source the uploader is configured with a size filter equal to the value the Media screen reports, so it should refuse a larger file before sending anything. A request therefore reaches a lower layer only when that layer’s limit is below the PHP value. That is read from the code, not run in a browser, and our curl requests skipped the browser check on purpose.

    What the Lab Did Not Cover

    An Apache reverse proxy with a body limit let the 2 MB request through, so we have no Apache measurement and make no claim from one. We also did not run LiteSpeed, Cloudflare, MySQL or multisite, and we did not run the browser uploader. Where this guide states those, it cites the documentation or the source instead.

    Fix the 413 Request Entity Too Large at the Layer That Answered

    Change the limit at the layer that returned the page, and keep the three values in a sensible order: the outer limit at least as large as the PHP body limit, which is at least as large as the PHP file limit. On shared hosting you control the PHP values, and the host controls the layers in front.

    If nginx Returned the 413 Request Entity Too Large

    The directive is client_max_body_size. The nginx documentation gives a default of 1m, says a larger request gets the 413, and says that a value of 0 turns the check off. It can be set in the http, server or location context, so a value in one place can be overridden in another. Set it a little above the largest upload you intend to allow, reload nginx, and repeat the upload.

    In the lab, client_max_body_size 64m; let a 2 MB file through and still stopped a 70 MB file, which is the behavior you want. Avoid 0 on a public site, because it removes the only brake on request size.

    If Apache Returned the 413 Request Entity Too Large

    The directive is LimitRequestBody, and the Apache core documentation lists a default of 1073741824 bytes, with 0 meaning unlimited. The same page says that in 2.4.53 and earlier the default was 0. The Apache 2.4 change log records the change in the 2.4.54 release: “Change default value of LimitRequestBody from 0 (unlimited) to 1GB.” An older server therefore allows any size and a newer one stops at 1 GiB.

    If Cloudflare Returned the 413 Request Entity Too Large

    Cloudflare’s page lists a maximum upload of 100 MB on Free and Pro, 200 MB on Business and up to 5 GB on Enterprise, and says the Maximum Upload Size can be adjusted from the zone’s Network page. When the file is above the plan limit, either change the setting where the plan allows it, or send the file by a route that avoids the proxy, such as SFTP.

    If PHP Returned the Message, It Was Not a 413 Request Entity Too Large

    A notice about upload_max_filesize or the “link has expired” page is a PHP answer. On our shared servers the PHP limits can be set in the cPanel MultiPHP INI Editor, and a .user.ini file is read by PHP, which by default re-reads it every 300 seconds, so a change can take up to five minutes. Our guide to the missing a temporary folder error lists the other messages PHP can print for an upload.

    When a Bigger Limit Is the Wrong Fix for a 413 Request Entity Too Large

    A size limit is a safety brake, and raising every layer to a huge number trades one problem for another. A handful of large files a year rarely justifies a permanent change, so consider the routes that never send the file through a browser request.

    • Where your plan includes SSH access, upload the file over SFTP, then register it with wp media import, which the WP-CLI reference describes as creating attachments from local files or URLs. No HTTP request body is involved, so no 413 is possible.
    • For very large files, use an uploader built on a resumable protocol such as tus, which splits one file into many small requests so that no single request meets a size limit.
    • For video, upload to a video service and embed it. A multi-gigabyte file in the Media Library also fills the plan’s disk quickly, and our post on the available disk space critically low warning shows what that looks like.
    • When you move a whole site, do not push the archive through the browser at all. Our guide to the migration to a new host compares four methods.

    What AHosting Can Do About a 413 Request Entity Too Large

    Once you know the layer, the fix is usually one line. The hard part on shared hosting is that the web server is the one layer you cannot edit. Our servers run LiteSpeed, and we have not published a request body figure for them, so we do not quote one here. If the Server header names LiteSpeed, or the 413 appears below your PHP limits, open a ticket with the exact words on the error page and the size of the file, and we will look at it with you.

    The shared plans on our web hosting page list SSH access, and the WordPress hosting plans list WP-CLI access, which is the route that avoids this error entirely. If you run several client sites, the reseller hosting plans are the page to compare.

    Frequently Asked Questions: 413 Request Entity Too Large

    What does a 413 request entity too large error mean on WordPress in 2026?

    Specifically, it means a server or proxy in front of WordPress refused the request because the body was bigger than that layer allows. WordPress itself never sends a 413. The layer decoder table in this guide lists the five places that can say no and what each one prints.

    Why does WordPress still show a 413 request entity too large error after I raise upload_max_filesize?

    In practice, upload_max_filesize is read by PHP, and the 413 is returned before PHP starts. In the lab a site set to 100 MB behind nginx with no extra setting rejected a 1 MB file, while the Media screen still said 100 MB. Change the limit at the layer that returned the page, not in PHP.

    Nginx vs Apache vs Cloudflare: which one returns the 413 request entity too large error?

    Typically, whichever has the lowest limit on the request path. Nginx ships with a 1 MB default, Apache has allowed up to 1 GiB since version 2.4.54, and Cloudflare allows 100 MB on the Free and Pro plans. Read the Server header on the failed request to see which one answered.

    413 request entity too large vs the link you followed has expired: how do I tell them apart in 2026?

    For example, a 413 comes back as a plain server page that names nginx, Apache or Cloudflare, while the expiry message is a WordPress page with HTTP status 403. In the lab a body over post_max_size produced the expiry message, not a 413. The first needs a web server or proxy change, and the second needs a PHP limit.

    How large can an upload be before Cloudflare returns a 413 request entity too large error on the Free plan in 2026?

    As a result of the plan table on the Cloudflare support page, the maximum upload size is 100 MB on Free and Pro, 200 MB on Business, and up to 5 GB on Enterprise. The same page says the Maximum Upload Size can be adjusted from the zone Network page. A file under the limit that still fails points to a layer closer to your site.

    What default limit makes nginx return a 413 request entity too large error for a WordPress upload?

    Specifically, the nginx documentation gives a default of 1m for the client_max_body_size directive. In the lab a 1 MB test file produced a request of 1,049,122 bytes, which is over 1,048,576, so nginx rejected it. Raising the value to 64m let a 2 MB file through and still rejected a 70 MB file.

    Can I fix a 413 request entity too large error myself on AHosting shared hosting?

    In practice, you can change the PHP limits yourself in the cPanel MultiPHP INI Editor, but a 413 is a web server answer and the web server is ours to manage. Open a ticket with the exact text of the 413 page, the size of the file and the page you were on, and we will look at it with you.

    Does AHosting WordPress hosting include WP-CLI so I can add a large file past a 413 request entity too large error?

    Indeed, the WordPress hosting page lists WP-CLI access, and the WP-CLI media import command creates attachments from local files. Upload the file over SFTP first, then import it, because that path never sends the file through a browser request. Check that your plan includes SSH access before you rely on it.

    What should I send AHosting support when a 413 request entity too large error blocks my upload?

    Specifically, send the exact words on the error page, the Server header from the browser Network tab, the size of the file in megabytes, and the address of the screen where it failed. Leave out passwords and database exports. Those four items tell us which layer answered without guessing.

    Why does the media uploader say the server cannot process the image when the real cause is a 413 request entity too large?

    Notably, WordPress maps every HTTP error status of 400 or higher to one generic uploader message, and for image files that message talks about a busy server and a 2560 pixel maximum. It does not mention the 413. Open the Network tab and read the status code of the failed request before you resize anything.

    October 26, 2026
  • Headers Already Sent in WordPress: Find the Byte | AHosting

    Headers Already Sent in WordPress: Find the Byte | AHosting

    • Headers Already Sent in WordPress: What PHP Is Refusing to Do
      • Headers Already Sent: The Second Path Names the Victim
    • How to Read Output Started At When Headers Already Sent Appears
    • Headers Already Sent After a BOM or a Stray Space
      • Check the First Three Bytes for Headers Already Sent
    • Headers Already Sent Because of Text After the Closing Tag
      • Remove the Closing Tag to Stop Headers Already Sent
    • Headers Already Sent Because Something Printed a Notice
      • When the Named File Is a Core File
    • Paste Your Headers Already Sent Warning Into the Decoder
    • Why Headers Already Sent Works on One Host and Fails on Another
      • Headers Already Sent After You Move Hosts
    • What Headers Already Sent Breaks: Login, Redirects and the REST API
      • The Cookies Are Blocked Due to Unexpected Output Error
      • Headers Already Sent in the REST API Response
      • Why the Front Page Looks Fine
    • Find the Stray Byte That Causes Headers Already Sent Across a Site
      • A Scanner for BOMs and Text After the Closing Tag
      • A Fix Order for Headers Already Sent
    • What the Headers Already Sent Lab Did Not Cover
    • Frequently Asked Questions About Headers Already Sent in WordPress
      • What does the headers already sent warning mean in WordPress in 2026?
      • Why does headers already sent appear in wp-admin and login but not on the front page?
      • Headers already sent: BOM vs closing tag whitespace, which one does the line number reveal?
      • Output buffering vs fixing the file: which is the right fix for headers already sent in 2026?
      • How do I find which plugin causes headers already sent when the path names a core file?
      • Why can't I edit the header in WordPress when the headers already sent warning shows?
      • Which AHosting plans list SSH access or WP-CLI for headers already sent troubleshooting?
      • What should I send AHosting support about a headers already sent warning in 2026?
      • Can I hide the headers already sent warning with a .user.ini file on AHosting shared hosting?
      • Is headers already sent a security problem or only a coding mistake in 2026?
    TL;DR

    The headers already sent warning means PHP had already sent a byte of page output when WordPress tried to send a header or a cookie. Read the path after "output started at" first, because it names the file and line where that byte left. A line number of 1 points to a BOM, a line near the end points to text after a closing tag, and a core file points to a notice printed above it. In our lab a 3 byte BOM produced six warnings and no login.

    Listen: the first path in the warning is the cause, and the line number says whether it is a BOM, a closing tag or a printed notice. By Matt Chrust, Director of Business Development, AHosting.

    Headers Already Sent in WordPress: What PHP Is Refusing to Do

    The headers already sent warning is PHP refusing to change an HTTP header after the page has started. A web response has two parts, the headers first and the body second. Once a single byte of body leaves PHP, the headers are locked, and a later call to header() or setcookie() fails. The PHP manual for header() says why: output can come from “blank lines in a file”, not only from HTML.

    Here is the full message, with a made-up path:

    Warning: Cannot modify header information - headers already sent by (output started at /home/user/public_html/wp-config.php:1) in /home/user/public_html/wp-login.php on line 525
    How one stray byte causes the headers already sent warning Step 1: PHP starts the response. Step 2: a stray byte such as a BOM, a space or a printed notice leaves PHP; the output started at path names this step. Step 3: the HTTP headers are now locked. Step 4: setcookie or header runs too late and prints the warning; the in file on line path names this step. 1 PHP starts the response 2 A stray byte leaves BOM, space, notice 3 The headers are now locked 4 setcookie or header runs too late: Warning Read this first "output started at" path Only the victim "in file on line" path Lab: WordPress 7.1.3, PHP 8.5.10 built-in server, one workstation

    Headers Already Sent: The Second Path Names the Victim

    The message has two halves, and only one of them helps. The first half, output started at, names the file and line where the first byte left PHP. That is the cause. The second half, in ... on line, names the code that tried to send a header and was too late. Core files appear there constantly, and editing them is the wrong move.

    To check this, I installed WordPress 7.1.3 on a local PHP 8.5.10 server and caused each problem on purpose. Every row of the tables below comes from one of those runs. The setup is a single workstation, not an AHosting server, and the last section lists what it did not cover.

    How to Read Output Started At When Headers Already Sent Appears

    Start with the file and the line number. Together they sort the problem into one of five cases, and each case has a different fix.

    What output started at namesMost likely causeWhat to checkReproduced in the lab
    A plugin, theme or wp-config.php file, line 1A BOM, or a space or line break before the PHP opening tagThe first three bytes of that fileYes. A BOM in wp-config.php gave six warnings and no login cookie
    A plugin or theme file, a line near the endText after the closing tag: a second newline or a spaceThe last lines of that fileYes. A closing tag plus two newlines was reported at line 5
    A plugin or theme file, a line in the middleThe code printed something: an echo, or a notice PHP displayedThe named line, then any message printed above the warningYes. A notice raised on line 2 was reported at line 2
    A core file such as wp-includes/functions.phpA Notice or Deprecated message printed by core for another pluginThe first message above the first warning; it names the real fileYes. A deprecated call was reported at functions.php line 6260
    Nothing is shown at alldisplay_errors is off, so the warning is hidden but the problem remainsThe PHP error log, and the login page error textYes. Login returned 200 with no cookie and an unexpected output error
    Headers Already Sent Decoder Table: five readings of the output started at path, each tied to a run on WordPress 7.1.3.

    Headers Already Sent After a BOM or a Stray Space

    A byte order mark, or BOM, is the character U+FEFF placed at the start of a file. In UTF-8 it is the three bytes EF BB BF, and the W3C article on the byte-order mark warns that a BOM at the start of a PHP file begins output before a header call runs. Some editors add it on save, and none shows it. PHP treats any bytes before the opening tag as output. The PSR-1 standard therefore requires PHP code to use UTF-8 without BOM.

    In the lab I put those three bytes before the opening tag of wp-config.php and submitted the login form with the right password. WordPress answered 200 and set no login cookie. It printed six warnings, all saying output started at wp-config.php:1. One invisible mark produced six messages, because each header and cookie call in the login request failed on its own.

    Check the First Three Bytes for Headers Already Sent

    A line number of 1 is the tell, but check before you edit. In a shell, head -c 3 wp-config.php | od -An -tx1 prints ef bb bf when the BOM is there. I ran that on macOS only. A space or tab before the opening tag shows up as 20 or 09 in the same output.

    To fix it, save the file again as UTF-8 without BOM. In VS Code, the encoding button in the status bar lets you save the file with a different encoding. Then request the page again and confirm that the first byte is the opening tag.

    Headers Already Sent Because of Text After the Closing Tag

    The closing tag is the second classic source. PHP swallows one newline that comes right after the closing tag, and anything beyond that newline is output. The lab shows the edge exactly: a must-use plugin ending in a closing tag plus one newline worked, and the same file with two newlines broke login.

    In that run the report said output started at the plugin file, line 5, although the file had four lines. Notably, the second newline sits on a fifth line that looks empty in an editor, which is why this one is hard to see.

    Remove the Closing Tag to Stop Headers Already Sent

    Because the closing tag at the end of a file is optional, leaving it off removes this whole class of error. The WordPress PHP coding standards say that omitting the closing tag at the end of a file is preferred. For a file you own, such as a custom plugin or a functions.php, delete the final closing tag and any lines below it.

    Do not edit a core file or a vendor plugin this way. Replace it with a clean copy from its author instead, because your change disappears at the next update anyway.

    Headers Already Sent Because Something Printed a Notice

    Whitespace is only one kind of output. A PHP notice, warning or deprecation message is output as well, and WordPress shows them in the page when debugging is on. The WordPress debugging handbook says the WP_DEBUG_DISPLAY default is true, which “shows errors and warnings as they are generated”. A site that shows one notice then shows a headers already sent warning right behind it.

    In the lab, a must-use plugin raised a notice on init with debugging on. Login returned 200 with no cookie, and the warning said output started at that plugin, line 2, the very line that raised the notice. So far the file named is the culprit.

    When the Named File Is a Core File

    The next run is the one that misleads people. A plugin called a deprecated function on init. WordPress printed the Deprecated message itself, so the warning said output started at wp-includes/functions.php:6260. Core is named, and core is innocent. The real file is in the message printed above the first warning.

    Read that first message, then rename the plugin folder it names and test again. To stop the display while you fix the cause, set WP_DEBUG_DISPLAY to false and WP_DEBUG_LOG to true. If a debug log stays on, read what a public debug log exposes so that you do not trade one problem for another.

    Paste Your Headers Already Sent Warning Into the Decoder

    The decoder below applies the table to your own warning. It reads the line number and the path, then names the likely cause and the section to read next. It reports what the table says and nothing more, so a plugin with unusual output still needs a person to read the file.

    Warning Line Decoder

    Paste the whole warning. The text stays in your browser and is not sent anywhere.

    Open the matching section

    Why Headers Already Sent Works on One Host and Fails on Another

    The same files can pass on one server and fail on another. The reason is output_buffering. The PHP output control settings list its default as “0” and give 4096 as an example value. With a buffer, PHP holds early output in memory, so headers can still go out first.

    I ran the same broken files with and without a 4096 byte buffer. The result is Table 2.

    Stray outputoutput_bufferingLogin result
    3 byte BOM in wp-config.php0200, no login cookie, six warnings
    3 byte BOM in wp-config.php4096302 redirect, login cookie set, no warning
    20 byte echo from a plugin4096302 redirect, login cookie set
    5000 byte echo from a plugin4096200, no login cookie, warning at the echo line
    3 byte BOM, display_errors off0200, no login cookie, no warning shown
    Same Files, Different PHP Settings: how output_buffering changes the login result in the lab.

    Headers Already Sent After You Move Hosts

    Because the setting belongs to the server, a migration can start this warning without anyone touching a file. A BOM that a lenient buffer hid for years surfaces the day the new server has none. If the warning appears right after a move, the migration walkthrough covers the checks around it, and the stray byte is still the thing to find.

    Raising the buffer would hide the symptom in the lab, and I would not ship it. The 5000 byte row shows the hiding stops working as soon as the output grows. I did not read this setting on any AHosting server, so this post makes no claim about its value there. Ask your host, or look at it in phpinfo().

    What Headers Already Sent Breaks: Login, Redirects and the REST API

    The warning is the visible part. The damage is what failed to send. In login, wp_set_auth_cookie() makes three setcookie() calls at pluggable.php:1193 to 1195, and all three failed in the lab. Redirects use header( "Location: ..." ) at pluggable.php:1542, and the admin sends a Referrer-Policy header at functions.php:7310. None of these has a guard.

    The Cookies Are Blocked Due to Unexpected Output Error

    Hiding the warning does not hide the failure. With display_errors off, the lab login page came back with “Cookies are blocked due to unexpected output.” These lines of wp-login.php print it when the login cookie is missing and headers_sent() is true. The error is the same problem seen from the login form.

    Headers Already Sent in the REST API Response

    REST responses need clean JSON. With a BOM in a must-use plugin, a REST request returned a body that began with the bytes ef bb bf, then warning markup, and a JSON parser rejected it. The editor shows that as a bad response, so the not a valid JSON response guide is the next place to look.

    Why the Front Page Looks Fine

    The front end is quieter. WordPress tests headers_sent() before it sends most front-end headers, at class-wp.php:573 to 581, and nocache_headers() returns early the same way. In the lab, the front page returned 200 and printed no warning, yet the stray byte still sat ahead of the doctype. A clean front page therefore does not clear a file.

    Redirect and login problems from cookies deserve their own check, and the too many redirects guide covers the cookie and redirect side separately.

    Find the Stray Byte That Causes Headers Already Sent Across a Site

    Usually the warning names the file, and you are done. Sometimes you migrate a site or inherit one, and you want every file checked at once. On a shared web hosting plan that lists SSH access, a short PHP script can do it. I wrote one and tested it on seven sample files.

    A Scanner for BOMs and Text After the Closing Tag

    It reads every .php file under a folder and prints two kinds of finding. A first token made only of a BOM or whitespace is reported with its bytes, and so is whitespace after a final closing tag. It left alone a closing tag followed by one newline, a file with no closing tag, and a template with real markup.

    <?php
    // Usage: php find-stray-output.php /path/to/wp-content
    $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($argv[1], FilesystemIterator::SKIP_DOTS));
    foreach ($it as $f) {
        if (substr($f, -4) !== '.php') { continue; }
        $t = token_get_all(file_get_contents($f));
        $first = $t[0];
        if (is_array($first) && $first[0] === T_INLINE_HTML && trim($first[1], "\xEF\xBB\xBF \t\r\n") === '') {
            echo $f . ':1 starts with ' . bin2hex(substr($first[1], 0, 6)) . "\n";
        }
        $last = end($t);
        $prev = prev($t);
        if (is_array($last) && $last[0] === T_INLINE_HTML && is_array($prev) && $prev[0] === T_CLOSE_TAG && trim($last[1]) === '') {
            echo $f . ' ends with ' . bin2hex(substr($last[1], 0, 6)) . " after the closing tag\n";
        }
    }

    The script is read-only. It cannot find an echo or a notice, so the decoder above still comes first. If you run many client sites, run it once per account, because a reseller hosting account keeps a separate cPanel account for each client.

    A Fix Order for Headers Already Sent

    1. Read the first warning, and ignore the repeats. They share one cause.
    2. On line 1, check the first three bytes and save the file as UTF-8 without BOM.
    3. Near the end of a file, delete the closing tag and any lines under it.
    4. With a core file, read the message printed above the first warning and fix the file it names.
    5. Test login in a private window, because a cached admin session hides the cookie failure.

    What the Headers Already Sent Lab Did Not Cover

    The lab used WordPress 7.1.3 with SQLite instead of MySQL, PHP 8.5.10 and the built-in web server, on one workstation. I did not test LiteSpeed, LSAPI or php-fpm, multisite, a cPanel editor, or any browser. The scanner ran on seven sample files, not on a real site, and the shell commands ran on macOS only. Every number in this guide comes from that setup, so treat the line numbers as WordPress 7.1.3 line numbers.

    Finally, if your warning fits none of the five rows, the file is not the problem and the next step is a person. If your site runs on our WordPress hosting plans, open a ticket with the full warning line, from the word Warning to the last line number, and we will look at it with you.

    Frequently Asked Questions About Headers Already Sent in WordPress

    What does the headers already sent warning mean in WordPress in 2026?

    Specifically, PHP had already sent page output when WordPress tried to send a header or a cookie, so PHP refused. The path after output started at names the file and line where the first byte left, and that is the place to look. The second path in the message only names the code that was too late.

    Why does headers already sent appear in wp-admin and login but not on the front page?

    In practice, WordPress core tests headers_sent before it sends most front-end headers, so the front end stays quiet. Login, admin screens and redirects call setcookie or header without that test, so they print the warning. The stray output can still be on the front page, ahead of the doctype.

    Headers already sent: BOM vs closing tag whitespace, which one does the line number reveal?

    Specifically, a line number of 1 points to a BOM or to text before the PHP opening tag. A line number near the end of a file points to text after the closing tag. In our lab a closing tag followed by two newlines was reported at line 5 of a file with four lines.

    Output buffering vs fixing the file: which is the right fix for headers already sent in 2026?

    Specifically, fixing the file is the right fix. Output buffering only holds early output in memory, and it stops helping once the output outgrows the buffer. In our lab a 20 byte echo passed with a 4096 byte buffer, and a 5000 byte echo failed with the same setting.

    How do I find which plugin causes headers already sent when the path names a core file?

    Specifically, scroll up to the first message printed above the first warning, because a Notice or Deprecated line names the real file. In our lab a deprecated call from a must-use plugin was reported at wp-includes functions.php line 6260, while the message above it named the plugin. Then rename that plugin folder and test again.

    Why can’t I edit the header in WordPress when the headers already sent warning shows?

    Indeed, this warning is about HTTP headers, the lines a server sends before the page, and not the header area you edit in the Customizer or the Site Editor. No theme setting changes it. The fix is in a PHP file that printed something too early, so use the path after output started at.

    Which AHosting plans list SSH access or WP-CLI for headers already sent troubleshooting?

    Specifically, the AHosting WordPress Hosting page lists WP-CLI access and SSH access (jailed shell), and the Web Hosting page lists SSH access (jailed shell), as read on October 20, 2026. Neither page says which tools exist inside the shell, so check that PHP runs there before you rely on a scanner.

    What should I send AHosting support about a headers already sent warning in 2026?

    Specifically, send the full warning line, from the word Warning to the last line number, including both paths. The line holds file paths for your account and nothing secret. If a notice printed above it, add that line too, and say which file you already checked.

    Can I hide the headers already sent warning with a .user.ini file on AHosting shared hosting?

    However, hiding the message does not fix the cause. Our servers read .user.ini files, so display_errors can be set there, but in our lab login still failed with display_errors off and WordPress printed that cookies are blocked due to unexpected output. Fix the file that printed the byte.

    Is headers already sent a security problem or only a coding mistake in 2026?

    Typically it is an editor or coding mistake, and a BOM does not prove a hack. That said, if the output at the named line is text you did not write, treat the file as suspect and compare it with a clean copy from the plugin or theme author.

    October 21, 2026
  • Sorry, You Are Not Allowed to Access This Page in WordPress: Find the Cause

    Sorry, You Are Not Allowed to Access This Page in WordPress: Find the Cause

    • Not Allowed to Access This Page: What WordPress Actually Checks
      • The Two Questions Behind the Message
      • The Three Causes at a Glance
    • Cause 1: Not Allowed to Access This Page Because the Page Is Not Registered
      • How to Confirm Cause 1 in Under a Minute
    • Cause 2: Not Allowed to Access This Page Because the Account Lost Its Role
      • Where WordPress Stores Your Role
      • Repair the Prefix in phpMyAdmin
      • Or Use WP-CLI Where the Plan Lists It
    • Cause 3: Not Allowed to Access This Page Because the Role Is Too Low
      • Why the Exact Sentence Matters
      • Give the Smallest Role That Works
    • Which Cause Do You Have? Check Your Symptoms
    • What the Lab Measured About Not Allowed to Access This Page
    • What Your Host Can and Cannot Change
    • Frequently Asked Questions: Not Allowed to Access This Page
      • What does the 403 error mean in WordPress when you are not allowed to access this page?
      • Why does WordPress 7.1 say you are not allowed to access this page after a plugin is deactivated in 2026?
      • Is a missing role vs a missing plugin page the reason you are not allowed to access this page in 2026?
      • Editor vs Administrator: which WordPress screens say you are not allowed to access this page?
      • Can I fix not allowed to access this page errors in phpMyAdmin on an AHosting cPanel account?
      • Does AHosting WordPress hosting include WP-CLI access to change a user role in 2026?
      • Which two database records decide whether WordPress 7.1.3 treats a user as an administrator?
      • Why does every wp-admin screen say you are not allowed to access this page after a migration to a new cPanel host?
      • Will AHosting support look at a not allowed to access this page error with me if I open a ticket?
      • How can I tell a WordPress 403 vs a web server 403 when I am not allowed to access this page?
    TL;DR

    WordPress prints "Sorry, you are not allowed to access this page." from one line in core, after one function answers no. That function refuses for three reasons: the page is not registered, your account has no role, or your role is too low. Open the Dashboard first. If it loads, check the plugin behind the address. If it fails too, the role records carry the wrong prefix.

    Not allowed to access this page: one function says no, for one of three reasons. By Matt Chrust, Director of Business Development, AHosting.

    Not Allowed to Access This Page: What WordPress Actually Checks

    When WordPress says you are not allowed to access this page, it has already decided, and it decided before the screen you asked for ran any code. The full sentence is “Sorry, you are not allowed to access this page.” It arrives with an HTTP 403 status and a plain error page.

    In WordPress 7.1.3, which I read and ran for this guide, one line in menu.php prints it. That line sits right after an if test. Therefore the real question is never why WordPress printed the message. It is why the function in that test returned false.

    The Two Questions Behind the Message

    The function is user_can_access_admin_page(), and its source in plugin.php asks two things. First, is the page registered? Second, does your account hold the capability that the menu entry demands?

    A page counts as registered when a plugin or core added it to the admin menu during that request. If the lookup finds no match, the function returns false at once. Otherwise it returns the result of current_user_can() for the capability stored on the menu entry. As a result, a stale bookmark and a low role end in the same sentence even though they have nothing in common.

    How WordPress 7.1.3 decides to show the not allowed message A request for a wp-admin screen loads menu.php, which removes menu entries the user lacks the capability for. Then user_can_access_admin_page checks that the page is registered and that the user holds the capability. If both are true the screen loads with status 200. If either is false, wp_die prints the message with status 403. 1. Request /wp-admin/screen 2. menu.php drops entries you lack 3. user_can_access_admin_page() registered? capability held? Both yes: screen loads, 200 the capability check passed Either no: wp_die(), 403 menu.php line 384 prints the message One function decides, and it asks two questions Source: WordPress 7.1.3, wp-admin/includes/menu.php and plugin.php

    The Three Causes at a Glance

    Every case I reproduced falls into one of three rows. Match your symptom in the first column, then jump to the section that carries the fix.

    What you seeWhat core checkedCauseWhere the fix is
    One plugin screen fails; the Dashboard opensIs the page in the registered list?The plugin is deactivated, removed or renamed, or the address is wrongCause 1: plugins screen or menu
    Every screen fails, Dashboard includedDoes the account hold the read capability?The account has no role: capabilities or roles records carry the wrong prefixCause 2: two database records
    Settings or Tools fails; Posts opensDoes the role hold manage_options?The role is real but too low for that menu entryCause 3: role change by an Administrator
    WordPress Admin Page Denial Decision Table: three causes of the message, from WordPress 7.1.3 source and the lab runs

    Cause 1: Not Allowed to Access This Page Because the Page Is Not Registered

    This is the cheapest cause to check, so check it first. A plugin adds its screen to the menu only while it is active. Deactivate the plugin, and the screen vanishes from the registered list on the next request.

    In the lab, an Administrator opened a test plugin page and got a normal 200. After I deactivated the plugin, the same address returned a 403 with the exact message. The Dashboard still returned 200 in the same session. An address that never existed, such as page=does-not-exist, produced the identical result.

    How to Confirm Cause 1 in Under a Minute

    1. Open the Dashboard at /wp-admin/. If it loads, your account still has a role, so cause 2 is unlikely.
    2. Open the Plugins screen and look for the plugin that owns the address. Compare the page name in the URL, after page=, with the plugin you expect.
    3. Reactivate the plugin, or reinstall it if an update removed it, then open its screen from the left menu instead of the saved bookmark.
    4. If the plugin is active and the screen is still refused, read cause 3. A plugin can register a page and still demand a capability you lack.

    Notably, a plugin update can rename its menu slug. Old emails and bookmarks then point at a slug that no longer exists. The message looks like a permissions problem, but nothing about your account changed.

    Cause 2: Not Allowed to Access This Page Because the Account Lost Its Role

    The second cause is the one that locks out an owner, and it can follow a migration. WordPress stores your role in the database, under a key that begins with the table prefix. If the prefix changes and the key does not, WordPress looks for your role under the new name and finds nothing.

    Where WordPress Stores Your Role

    Two records matter. The user meta table holds one row per user whose key is the prefix plus capabilities, and core builds that key at class-wp-user.php line 488. The options table holds one row whose name is the prefix plus user_roles, built at line 342 of class-wp-roles.php.

    With the default prefix those names are wp_capabilities and wp_user_roles. After a move to a site whose prefix is different, WordPress reads the new names. Specifically, the old rows stay in the tables under the old names, and nothing reads them.

    I tested all three combinations in the lab, after rewriting the stored keys from wp_ to xy_ while the tables kept wp_. An Administrator got a 403 with the exact message on the Dashboard, on Settings and on Plugins whether the old prefix sat on the user meta rows only, on the roles option only, or on both. In other words, either record alone is enough to lock you out.

    Repair the Prefix in phpMyAdmin

    The AHosting shared hosting plan page lists phpMyAdmin, and cPanel opens it from the Databases section. Work through these steps in order, and stop after the export if anything looks unfamiliar.

    1. Export the whole database from the Export tab. The UPDATE statements below cannot be undone.
    2. Read $table_prefix in wp-config.php. That is the prefix your tables use, and it is the one the keys must carry. Call it NEWPREFIX.
    3. In the users meta table, find a row whose key ends in _capabilities and read its prefix. That is your old prefix. Call it OLDPREFIX.
    4. Open the SQL tab, paste the two statements below with both prefixes replaced, and run them one at a time.
    5. Reload /wp-admin/. The Dashboard should open at once, because the rows are read on every request.
    UPDATE NEWPREFIX_usermeta
    SET meta_key = REPLACE(meta_key, 'OLDPREFIX_', 'NEWPREFIX_')
    WHERE meta_key LIKE 'OLDPREFIX\_%';
    
    UPDATE NEWPREFIX_options
    SET option_name = 'NEWPREFIX_user_roles'
    WHERE option_name = 'OLDPREFIX_user_roles';

    The first statement renames every user meta key that starts with the old prefix, which includes the capabilities and user level rows. The second renames the roles option. In the lab, the same two statements, written for SQLite and with the prefixes swapped, returned the Dashboard and Settings to 200 after the break. SQLite’s replace() function works the way the MySQL one does here, but I did not run the statements on MySQL itself.

    Or Use WP-CLI Where the Plan Lists It

    The AHosting WordPress hosting page lists WP-CLI access and a jailed SSH shell. The documented command is wp user set-role, which sets the role of one user. It repairs that user only. It does not touch the roles option, and the lab showed that a stale roles option alone locks everyone out.

    Therefore, use WP-CLI for a single account whose own row is wrong, and use the SQL for a whole site that moved. If you are unsure which describes you, the Dashboard test in the widget below usually decides it. For the move itself, the migration walkthrough compares four ways to migrate WordPress to a new host. For a first look at phpMyAdmin queries, the autoloaded options guide shows the tool in use.

    Cause 3: Not Allowed to Access This Page Because the Role Is Too Low

    The third cause is the least dramatic. Your account has a role, and the role is simply too low for that menu entry. WordPress is doing exactly what it should.

    In core, Settings requires manage_options (wp-admin/menu.php line 405), while the Dashboard needs only read (line 29). In the lab, an Editor opened Posts with a 200 and was refused on Settings with a 403 and the exact message. The same Editor was refused on a test plugin page registered with manage_options.

    Why the Exact Sentence Matters

    Other refusals use other words. For example, the Editor who asked for the Users screen got a 403 with “Sorry, you are not allowed to list users.” from a different line of core. The sentence you read therefore points at a mechanism, so copy it exactly when you search or write to anyone.

    Give the Smallest Role That Works

    Raising everyone to Administrator makes the message disappear, and it is the wrong fix. NIST defines least privilege as granting each user the minimum authorizations needed for the job. An Editor who needs one plugin screen should get that capability through a role plugin or a custom role, not the keys to the whole site.

    Agencies meet this case directly when a client holds an Editor account and asks for Settings. If you manage many client sites, the reseller hosting page describes the account structure, and the open registration guide explains why the default role for new users must stay low.

    Which Cause Do You Have? Check Your Symptoms

    The four questions below follow the decision table. The result names the likeliest cause and points at the section with the fix. It reads nothing from your site, so every answer comes from you.

    Find Your Cause in Four Questions

    Answer the questions above and the likely cause appears here.
    Read the matching fix

    What the Lab Measured About Not Allowed to Access This Page

    The numbers below come from a lab on one workstation, not from an AHosting server. I installed WordPress 7.1.3 on PHP 8.5.10 with the SQLite database plugin from WordPress.org, created an Administrator, an Editor and a user with no role, and requested each page with curl. The results are about how core behaves, and they say nothing about our hosting accounts.

    StateRequestStatusExact message
    AdministratorSettings screen200No
    EditorSettings screen403Yes
    User with no roleDashboard403Yes
    EditorDashboard200No
    EditorPlugin page needing manage_options403Yes
    Administrator, plugin activeThat plugin page200No
    Administrator, plugin deactivatedThat plugin page403Yes
    AdministratorAddress that never existed403Yes
    Administrator, old prefix on either or both recordsDashboard, Settings, Plugins403Yes
    EditorUsers screen403No: a different sentence
    WordPress 7.1.3 lab results: ten states, with the status code and whether the exact message appeared

    Two limits apply. I did not test multisite, a real migration plugin, or MySQL, and I did not test an HTTPS or domain change. Therefore this guide makes no claim about those cases.

    What Your Host Can and Cannot Change

    No host can change which roles may open which screens, because that logic lives in WordPress. A host can give you the tools to repair the records, and it can read the evidence with you. That is the useful boundary.

    If the login itself loops instead of refusing you, that is a different failure. In that case read the redirect loop guide, because the fix lives in a redirect rule, not in a role.

    If the fix above did not work, open a ticket with the exact address you were opening and the role your account shows on the Users screen, and we will look at it with you. Please leave out passwords and database exports. Neither is needed to read the cause.

    Frequently Asked Questions: Not Allowed to Access This Page

    What does the 403 error mean in WordPress when you are not allowed to access this page?

    Specifically, the 403 is the HTTP status WordPress sends with the message after it checks your account against the admin menu. It means WordPress ran, found the page, and refused you, so the cause sits in your plugins, your role or your database, not in the web server. The decision table in this guide matches each symptom to its fix.

    Why does WordPress 7.1 say you are not allowed to access this page after a plugin is deactivated in 2026?

    In practice, a deactivated plugin stops registering its menu page, so the saved bookmark points at a page WordPress no longer knows. In the lab, an administrator got a 403 with the exact message on that URL and a normal 200 on the Dashboard. Reactivate the plugin, or open the screen from the menu instead of the bookmark.

    Is a missing role vs a missing plugin page the reason you are not allowed to access this page in 2026?

    Specifically, you can tell them apart with one request. A missing role fails every wp-admin screen including the Dashboard, while a missing plugin page fails only that one address and the Dashboard still opens. Open the Dashboard first, then read the rest of the guide for the matching fix.

    Editor vs Administrator: which WordPress screens say you are not allowed to access this page?

    For example, an Editor can open Posts but gets the message on Settings, because the Settings menu entry requires the manage_options capability and the Editor role does not carry it. An Administrator opens both. The lab table in this guide lists the exact requests and the results.

    Can I fix not allowed to access this page errors in phpMyAdmin on an AHosting cPanel account?

    Specifically, yes, when the cause is a prefix mismatch. The AHosting plan pages list phpMyAdmin, so two UPDATE statements can rewrite the old prefix in the user meta table and in the roles option. Export the database first, because an UPDATE cannot be undone, and replace the example prefixes with your own.

    Does AHosting WordPress hosting include WP-CLI access to change a user role in 2026?

    Specifically, the AHosting WordPress hosting page lists WP-CLI access and a jailed SSH shell, so the documented command wp user set-role can change one account. It writes only that user, though, and the lab showed a stale roles option alone is enough to lock out every user. Check the plan page for your own account before relying on it.

    Which two database records decide whether WordPress 7.1.3 treats a user as an administrator?

    Specifically, one is the user meta row named after the table prefix plus capabilities, and the other is the options row named after the prefix plus user_roles. The first says which role the user holds, and the second says what that role may do. If either row carries the wrong prefix, WordPress finds no capabilities and refuses every admin screen.

    Why does every wp-admin screen say you are not allowed to access this page after a migration to a new cPanel host?

    Specifically, the likely cause is a table prefix that changed in the move, or tables imported under a different one, while the stored keys still carry the old prefix. WordPress builds the capabilities key from the current prefix, finds nothing, and treats your account as having no role. All three prefix cases in the lab returned the message on the Dashboard, the Settings screen and the Plugins screen.

    Will AHosting support look at a not allowed to access this page error with me if I open a ticket?

    Specifically, yes. Open a ticket with the exact address you were opening and the role your account shows on the Users screen, and we will look at it with you. Please leave out passwords and database exports, because neither is needed to read the cause.

    How can I tell a WordPress 403 vs a web server 403 when I am not allowed to access this page?

    In practice, read the page itself. The WordPress version carries the sentence Sorry, you are not allowed to access this page and the browser title WordPress Error, because WordPress printed it. A 403 page without that sentence was produced before WordPress ran, so changing roles or prefixes will not help.

    October 20, 2026
  • ERR_TOO_MANY_REDIRECTS in WordPress: Find the Looping Rule With curl

    ERR_TOO_MANY_REDIRECTS in WordPress: Find the Looping Rule With curl

    • What ERR_TOO_MANY_REDIRECTS Means in WordPress
      • Why the ERR_TOO_MANY_REDIRECTS Loop Is Rarely a WordPress Bug
    • Read the ERR_TOO_MANY_REDIRECTS Chain With curl Before You Change Anything
      • The Redirect Loop Signature Table for ERR_TOO_MANY_REDIRECTS
    • Cause 1: A Force-HTTPS Rule Behind a Proxy Causes ERR_TOO_MANY_REDIRECTS
      • How WordPress Decides a Request Is HTTPS
      • The wp-config.php Fix for This ERR_TOO_MANY_REDIRECTS Loop
      • The Second Way Out of This ERR_TOO_MANY_REDIRECTS Loop
    • Cause 2: FORCE_SSL_ADMIN Produces an ERR_TOO_MANY_REDIRECTS Loop on wp-admin Only
    • Cause 3: A www and Non-www Fight Creates an ERR_TOO_MANY_REDIRECTS Loop
      • Why the Scheme Alone Rarely Triggers This One
    • Cause 4: Two HTTPS Rules Cause the Last ERR_TOO_MANY_REDIRECTS Pattern
    • What Our ERR_TOO_MANY_REDIRECTS Lab Measured
    • A Five-Step ERR_TOO_MANY_REDIRECTS Fix Order That Avoids Guessing
    • What to Record Before You Ask for Help With ERR_TOO_MANY_REDIRECTS
    • When ERR_TOO_MANY_REDIRECTS Points at Something You Cannot Edit
    • Frequently Asked Questions: ERR_TOO_MANY_REDIRECTS in WordPress
      • How do I fix ERR_TOO_MANY_REDIRECTS on a WordPress site?
      • Why does ERR_TOO_MANY_REDIRECTS appear only on wp-admin and the login page in 2026?
      • Does a 301 vs 302 status matter when debugging an ERR_TOO_MANY_REDIRECTS loop?
      • Should an .htaccess rule vs the WordPress address setting force HTTPS in 2026 without an ERR_TOO_MANY_REDIRECTS loop?
      • Will moving to AHosting stop an ERR_TOO_MANY_REDIRECTS loop that started on my old host?
      • What should I send AHosting support for an ERR_TOO_MANY_REDIRECTS loop in 2026?
      • Can page caching on AHosting hide or cause an ERR_TOO_MANY_REDIRECTS loop in wp-admin?
      • How many redirects does a browser follow before showing ERR_TOO_MANY_REDIRECTS?
      • Why does ERR_TOO_MANY_REDIRECTS appear after I set www as the preferred domain?
      • Can HSTS keep an ERR_TOO_MANY_REDIRECTS loop alive after I fix the server in 2026?
    TL;DR

    ERR_TOO_MANY_REDIRECTS means two layers keep sending the browser to each other. Run curl -sIL once, read the Location headers, and the repeating pair names the layer to fix.

    isten: an ERR_TOO_MANY_REDIRECTS loop is two rules disagreeing, and the redirect chain shows which two. By Matt Chrust, Director of Business Development, AHosting.

    What ERR_TOO_MANY_REDIRECTS Means in WordPress

    ERR_TOO_MANY_REDIRECTS is the browser telling you that a request was redirected, and the redirect was redirected, and so on until it gave up. The message is not a WordPress error. WordPress is one of the two parties in the argument, and finding the other party is the whole job.

    The give-up point is a published number. The Fetch standard says that when a request’s redirect count reaches 20 the browser returns a network error (Fetch standard, HTTP-redirect fetch), and Chromium sets its own limit to 20 (Chromium url_request.h).

    Why the ERR_TOO_MANY_REDIRECTS Loop Is Rarely a WordPress Bug

    A loop needs two rules that each think they are right. One says the canonical address is HTTPS, the other cannot tell that the visitor already arrived over HTTPS. Or one says www, and another says non-www. WordPress ships with parts of both rules, which is why the loop looks like a WordPress problem, but the second rule is almost always something you or a layer in front of the site added.

    Read the ERR_TOO_MANY_REDIRECTS Chain With curl Before You Change Anything

    Do not start by disabling plugins. Start by looking at the chain, because the chain tells you which of four causes you have. In a terminal, run curl -sIL --max-redirs 5 https://example.com/wp-admin/, replacing the address with the failing one. The -I flag asks for headers only, -L follows redirects, and --max-redirs 5 stops the output after five hops so you can read it.

    curl keeps no cache, so it shows what the server sends today, not what your browser remembers from an hour ago. Read only the Location lines. A loop is any URL that shows up twice.

    The Redirect Loop Signature Table for ERR_TOO_MANY_REDIRECTS

    We reproduced the first three loops below in a lab and recorded the Location pattern each one prints. The fourth row is the pattern expected when two rules point opposite ways, and we did not reproduce it. Match your curl output to a row, then jump to the section named in the last column.

    What repeats in the Location linesWhere the loop appearsLikely causeSection
    The same https:// URL, foreverEvery pageA force-HTTPS rule that cannot see HTTPS behind a proxyCause 1
    The same https:// URL for /wp-admin/ onlyLogin and dashboardFORCE_SSL_ADMIN with is_ssl() falseCause 2
    https://www. then https:// then https://www.Front-end pagesHome URL host and a second rule disagree about wwwCause 3
    http:// to https:// to http://Every pageTwo HTTPS rules in different layers pointing opposite waysCause 4
    The Redirect Loop Signature Table: four ERR_TOO_MANY_REDIRECTS loop patterns and where to look first.

    Cause 1: A Force-HTTPS Rule Behind a Proxy Causes ERR_TOO_MANY_REDIRECTS

    This is the loop to rule out first whenever a CDN or reverse proxy sits in front of the site, and it is the one the diagram below shows. A CDN or reverse proxy accepts the visitor over HTTPS, then talks to your server over plain HTTP. A force-HTTPS rule at the origin sees an HTTP request, answers with a 301 to the HTTPS address, and the visitor comes straight back to the proxy. The origin never learns the visitor was already secure.

    How a TLS-terminating proxy turns a force-HTTPS rule into an ERR_TOO_MANY_REDIRECTS loop Three boxes in a row: Browser, Proxy or CDN, WordPress origin. Arrows show HTTPS from browser to proxy, plain HTTP from proxy to origin, and a 301 to HTTPS coming back to the browser, repeating until the browser stops at its redirect limit. Browser asks for https:// Proxy or CDN ends TLS here WordPress is_ssl() is false HTTPS plain HTTP 301 to https:// … and the browser starts again After 20 redirects the browser gives up and shows ERR_TOO_MANY_REDIRECTS

    How WordPress Decides a Request Is HTTPS

    WordPress reads two server variables. The function is_ssl() returns true when $_SERVER['HTTPS'] is on or 1, or when no HTTPS variable exists and the port is 443 (WordPress 7.1.3, load.php lines 1659 to 1673). It does not read the X-Forwarded-Proto header a proxy adds. Behind a proxy that ends TLS, both variables describe the plain HTTP leg, so is_ssl() is false on every request.

    The wp-config.php Fix for This ERR_TOO_MANY_REDIRECTS Loop

    The WordPress developer documentation describes exactly this case: a site behind a reverse proxy that provides SSL, itself hosted without SSL, sends requests into an infinite redirect loop, and the remedy is to configure WordPress to recognize HTTP_X_FORWARDED_PROTO (Administration Over SSL). In practice that means a few lines in wp-config.php, above the require_once for wp-settings.php: if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) { $_SERVER['HTTPS'] = 'on'; }. Our lab used the same logic and it turned 51 requests into one (results below). Only use it when every request really arrives through your proxy, because a client that reaches the origin directly could send that header itself. Some proxies send a comma-separated list such as http,https, which the same page warns about, so test the value you actually receive.

    The Second Way Out of This ERR_TOO_MANY_REDIRECTS Loop

    The header trick is one fix, and changing the connection is the other. If the proxy connects to your server over HTTPS instead of plain HTTP, the web server itself reports a secure request, so is_ssl() is true with no code change at all. Which of the two you choose depends on whether the origin has a valid certificate for the proxy to connect to, and on who controls the proxy settings. Either way the goal is identical: the layer that decides to redirect must be told what the visitor actually used.

    On Cloudflare this choice has a name: the SSL/TLS encryption mode. Flexible is the mode that produces this loop, because Cloudflare serves the visitor over HTTPS and then fetches from your origin over plain HTTP, which is exactly the arrangement the diagram above shows. In the Cloudflare dashboard, select the site, open SSL/TLS, then Overview, and change the mode from Flexible to Full (strict). Full (strict) requires a valid certificate on the origin, while Full accepts a self-signed one and still encrypts the leg to your server. Change the mode first and retest with curl before you edit wp-config.php, because the header fix ends the loop while leaving the connection to your server unencrypted.

    Cause 2: FORCE_SSL_ADMIN Produces an ERR_TOO_MANY_REDIRECTS Loop on wp-admin Only

    If the public pages load and only /wp-admin/ or wp-login.php loops, suspect this cause first. Two places in core redirect to HTTPS when FORCE_SSL_ADMIN is on and is_ssl() is false. The login file does it at line 15 of wp-login.php, and auth_redirect() does it for dashboard URLs at lines 1281 and 1293 of pluggable.php (WordPress 7.1.3).

    The front end is untouched because neither code path runs there. That asymmetry is the clue, and it is why people lose an afternoon editing public-page rules that were never involved. The fix is the same as Cause 1, since both come from is_ssl() being false behind a TLS-terminating layer: make the HTTPS variable reflect the real request before wp-settings.php loads.

    Cause 3: A www and Non-www Fight Creates an ERR_TOO_MANY_REDIRECTS Loop

    WordPress sends the browser to the host in its Home URL setting. The canonical redirect takes its target host from home_url() (canonical.php lines 602 to 605), and it only acts when the difference is no-www versus yes-www (lines 731 to 738). If your Home URL says www and another layer sends www traffic to the bare domain, the two bounce between hosts.

    The second rule can be a redirect in a DNS or proxy panel that was set up before the WordPress address changed, or the reverse. The signature is easy to spot in curl: the Location lines alternate between two hostnames. Pick one host, then set that host in the Home URL setting and in every rule that mentions it.

    Why the Scheme Alone Rarely Triggers This One

    The canonical comparison arrays hold host, path, port and query, and no scheme (canonical.php lines 740 to 750). So a scheme mismatch by itself does not make redirect_canonical() loop. It also runs only on the front end, because the function returns early when is_admin() is true (line 63), which matches the pattern that a www loop breaks public pages while the dashboard keeps working.

    Cause 4: Two HTTPS Rules Cause the Last ERR_TOO_MANY_REDIRECTS Pattern

    A site can end up with a force-HTTPS rule in .htaccess, another from a security or SSL plugin, and a third in the proxy panel. When they all agree, nobody notices. When one of them uses a different host or a different port, the browser alternates between two targets.

    Apache’s own documentation says a redirect in a dedicated HTTP virtual host is the cleanest approach to forcing HTTPS, with a mod_rewrite alternative for .htaccess use (Apache mod_rewrite: when not to use it). The practical rule that follows is simple: one force-HTTPS rule, in one place. Where you cannot edit the virtual host, the single rule lives in .htaccess or in the plugin, never both. Our guide to free SSL and domain management covers where certificates and domain redirects normally sit.

    What Our ERR_TOO_MANY_REDIRECTS Lab Measured

    We reproduced three of the loops on 19 October 2026 so the numbers in this guide are first-hand. The setup was a PHP 8.5.10 origin that uses WordPress 7.1.3’s own is_ssl() and the redirect branches quoted above, a small TLS edge that ends HTTPS and forwards plain HTTP with X-Forwarded-Proto: https, and curl following redirects. It is a lab on one machine, not a customer site, and it is labeled that way so nobody reads it as production data.

    Lab caseRedirects followedRequests the origin loggedOutcome
    Force-HTTPS rule behind the edge5051curl stopped: Maximum (50) redirects followed
    FORCE_SSL_ADMIN branch on /wp-admin/5051Same stop, only on the dashboard path
    www to non-www edge rule vs canonical host5051 (26 non-www, 25 www)Hosts alternated on every hop
    Same rule with X-Forwarded-Proto trusted first01HTTP 200 on the first request
    Lab results, 19 October 2026: three loops reproduced and one fixed with the X-Forwarded-Proto line.

    Two things stand out. Each loop costs the origin one request per hop, so a browser that stops at 20 redirects will have cost the origin about 21 requests, which is a quiet source of server load on a busy site. And the fix for the proxy case changed the result from 51 requests to one.

    A Five-Step ERR_TOO_MANY_REDIRECTS Fix Order That Avoids Guessing

    1. Run curl -sIL --max-redirs 5 on the failing URL and write down the repeating Location values.
    2. Match them to the signature table, then change one rule only.
    3. Retest with curl, then in a private window, so a remembered redirect or an HSTS upgrade does not hide your fix (how HSTS works).
    4. If the loop only appears after a move, compare the redirect rules on the old and new site, starting with our WordPress migration steps.
    5. Only now disable plugins one at a time, because a plugin that adds a redirect will show up as a rule in the chain.

    If you run a CDN in front of the site, our guide to LiteSpeed Cache and a CDN together lists the settings that tend to collide with an HTTPS redirect.

    ERR_TOO_MANY_REDIRECTS Loop Diagnoser

    Show the likely cause
    Pick both answers, then press the button.

    What to Record Before You Ask for Help With ERR_TOO_MANY_REDIRECTS

    A loop report is only as useful as the evidence attached to it. Collect four things first, because each one rules out a cause in seconds. The exact URL that loops, copied from the address bar. The full output of curl -sIL --max-redirs 5 for that URL. Whether a CDN, proxy or DNS-level redirect service sits in front of the site. And the last change made before it started, whether that was a migration, a new SSL plugin, or an edit to the WordPress Address or Site Address fields.

    That last item matters more than it looks. A loop that begins right after a change was almost certainly caused by that change, and reversing it is faster than any diagnosis. The signature table then tells you what you reversed, which is how you avoid repeating it.

    When ERR_TOO_MANY_REDIRECTS Points at Something You Cannot Edit

    Some loops live in a layer you do not control: a proxy panel, a reseller’s DNS service or a managed-hosting rule. When the curl output names a hostname that your account does not manage, you are done diagnosing and the next step is a ticket with that output attached. If your hosting and TLS arrangement is the open question, our SSL certificate options page and the shared hosting plans list what each plan includes.

    For the hosting side of a WordPress setup, see our WordPress hosting plans. If the loop is already live and the curl output is in front of you, open a ticket with that output, with any Set-Cookie lines removed, and we will look at it with you.

    Frequently Asked Questions: ERR_TOO_MANY_REDIRECTS in WordPress

    How do I fix ERR_TOO_MANY_REDIRECTS on a WordPress site?

    Specifically, run curl -sIL on the failing URL and read the Location headers. The two URLs that repeat name the two layers fighting, and the fix is to make one layer stop redirecting.

    Why does ERR_TOO_MANY_REDIRECTS appear only on wp-admin and the login page in 2026?

    Typically because FORCE_SSL_ADMIN is on while WordPress cannot see that the request arrived over HTTPS. The login code redirects to HTTPS, the proxy forwards plain HTTP again, and the loop never ends. The signature table above shows the curl output to expect.

    Does a 301 vs 302 status matter when debugging an ERR_TOO_MANY_REDIRECTS loop?

    In practice, it matters for the browser, not for the cause. A browser may remember a permanent redirect, so test with curl or a private window, because curl keeps no cache and shows every hop as the server sends it.

    Should an .htaccess rule vs the WordPress address setting force HTTPS in 2026 without an ERR_TOO_MANY_REDIRECTS loop?

    Ultimately, use one place only. Apache documents a redirect in a dedicated HTTP virtual host as the cleanest approach, with mod_rewrite as the .htaccess alternative, and a second HTTPS rule in a plugin or proxy is how the loops start.

    Will moving to AHosting stop an ERR_TOO_MANY_REDIRECTS loop that started on my old host?

    In fact, not by itself, because the loop comes from redirect rules that travel with the site files and database. Instead, compare the curl chain before and after the move, and check the migration steps in our migration guide before changing any rule.

    What should I send AHosting support for an ERR_TOO_MANY_REDIRECTS loop in 2026?

    In particular, send the output of curl -sIL –max-redirs 5 on the failing URL with any Set-Cookie lines removed, plus whether a CDN or proxy sits in front of the site. That output shows which hostnames and schemes repeat, so nobody has to guess the cause.

    Can page caching on AHosting hide or cause an ERR_TOO_MANY_REDIRECTS loop in wp-admin?

    In contrast to public pages, a logged-in admin session is uncacheable, so every wp-admin request reaches PHP and the redirect code runs each time. Caching therefore neither causes nor cures that loop, and the fix lives in the redirect rules.

    How many redirects does a browser follow before showing ERR_TOO_MANY_REDIRECTS?

    Specifically, the Fetch standard stops at 20 redirects and Chromium sets its limit to 20. Command-line curl follows up to 50 by default when you ask it to follow redirects, which is why a loop shows a count of 50 there.

    Why does ERR_TOO_MANY_REDIRECTS appear after I set www as the preferred domain?

    Notably, WordPress sends non-www requests to the host in its Home URL setting, so a second rule that sends www back to non-www at the DNS panel, proxy or .htaccess makes the two bounce forever. Keep one preferred host in both places.

    Can HSTS keep an ERR_TOO_MANY_REDIRECTS loop alive after I fix the server in 2026?

    Indeed, a site that sent an HSTS header makes the browser upgrade http:// URLs for that domain to HTTPS on its own, so an HTTP-based test can behave differently in the browser than in curl. Retest with curl and a fresh private window before changing rules again.

    October 19, 2026
  • Open Registration With Privileged Default Role? What Site Health Is Telling You

    Open Registration With Privileged Default Role? What Site Health Is Telling You

    • Open Registration With Privileged Default Role: What It Means in Site Health
    • How Open Registration With Privileged Default Role Gets Set Without the Settings Screen
    • How to Fix Open Registration With Privileged Default Role in Two Minutes
      • Change the two options in Settings, General
      • Read the open registration options directly in the database
    • Check Whether Anyone Used Your Open Registration
      • What to do about an account you did not create
    • Which Default Roles Trigger the Open Registration With Privileged Default Role Warning
    • Why Author and Contributor Pass the Open Registration With Privileged Default Role Check
    • What Site Health Cannot Tell You About Open Registration
    • When Open Registration Is Intentional: Choosing a Safe Default
    • Check Your Settings for Open Registration With Privileged Default Role
    • Keep Registration Closed Without Another Plugin
    • Frequently Asked Questions About Open Registration With Privileged Default Role
      • What does open registration with privileged default role mean in WordPress 2026?
      • Is open registration with privileged default role a real risk when Anyone can register is checked?
      • How do I fix open registration with privileged default role in 2026 if Settings will not save?
      • What are the default user roles in WordPress for new registrations?
      • Editor vs Administrator as the default role: which one triggers open registration with privileged default role?
      • Subscriber vs Contributor in 2026: which default role is safer after open registration with privileged default role is fixed?
      • Who can change the options behind open registration with privileged default role on an AHosting account?
      • Can I open a ticket with AHosting about open registration with privileged default role on my site?
      • Do AHosting accounts see the same open registration with privileged default role check as any other host?
      • Why does Site Health 7.1.3 pass an Author default role under open registration with privileged default role?
    TL;DR

    Open registration with privileged default role means anyone can sign up and become an Editor or Administrator. Set New User Default Role to Subscriber in Settings, General, then check Users for accounts you did not create.

    Listen: the Site Health registration warning compares two role names, and the Settings screen cannot have set it. By Matt Chrust, Director of Business Development, AHosting.

    Open Registration With Privileged Default Role: What It Means in Site Health

    Open registration with privileged default role is a critical Security item that WordPress 7.0 added to Tools, Site Health. It appears when two options in your database agree on something dangerous: anyone may register, and every new account lands as an Editor or an Administrator. We read the check in WordPress 7.1.3 to see exactly what it compares, and what we found changes what you should do first.

    The short version is a two-minute fix followed by a check you should not skip. This guide covers both, plus a gap in the test itself: it flags two roles and quietly passes three that can still hurt you.

    Here is the mechanism. The option users_can_register controls the Anyone can register box, and default_role controls New User Default Role. The registration form never asks a visitor which role they want. It calls wp_create_user() with a name, a password and an email, and wp_insert_user() then fills in the role from default_role. Combine a public form with a powerful default, and a stranger gets a privileged account in one submission.

    Site Health runs the check as a direct test when the screen loads. It reads both options with get_option(), and the item turns critical only when users_can_register is truthy and default_role is exactly editor or administrator, per the check in WordPress 7.1.3. The description it prints reads: Registration is open to anyone, and the default role is set to a privileged role.

    Which default roles Site Health flags A two-row grid. With Anyone can register off, all five roles show Good. With it on, Subscriber and Contributor show Good, Author shows Good but can publish, and Editor and Administrator show Critical. What the Site Health check evaluates Two options: users_can_register and default_role. Result shown by WordPress 7.1.3. Subscriber Contributor Author Editor Administrator Anyone can register: off Anyone can register: on Good Good Good Good Good Good Good Goodbut can publish Critical Critical Only Editor and Administrator turn the item critical. Amber means the item stays green while the risk remains.

    How Open Registration With Privileged Default Role Gets Set Without the Settings Screen

    Because the Settings screen no longer lets you choose a privileged default, a site that shows this item had its options written some other way. WordPress 7.0 added a filter named default_role_dropdown_excluded_roles and set it to exclude administrator and editor from the dropdown, according to the General Settings source. The one exception is a role that is already saved: it stays in the list so you can see it and change it.

    That leaves a short list of ways the combination appears:

    • The site chose Editor before the exclusion arrived in WordPress 7.0, and nobody has revisited the value since.
    • A plugin, theme or code snippet wrote the option with update_option(), or a migration or staging copy carried an old value over.
    • Someone with Administrator or database access edited the row directly.
    • A snippet emptied the exclusion filter, so the dropdown offers Editor again and an Administrator picked it.

    The check cannot tell you which of these happened. It reads two values and has no history. Treat it as a configuration error until the Users screen says otherwise, and read the account check below before you close the item.

    How to Fix Open Registration With Privileged Default Role in Two Minutes

    Change the two options in Settings, General

    1. Log in as an Administrator and open Settings, then General.
    2. Find the Membership row. If you do not need public sign-ups, untick Anyone can register.
    3. If you do need sign-ups, set New User Default Role to Subscriber.
    4. Click Save Changes, then reload Tools, Site Health and open the Status tab to run the check again.

    On a Multisite network the Membership row does not appear on the single-site General screen, because the source only renders it when is_multisite() is false. The test still reads the site-level options on a network, and its Change these settings link points to that same screen, so network owners will need the database method below.

    Read the open registration options directly in the database

    If the Settings screen will not load or will not save, read the values where they live. In phpMyAdmin or any database tool your plan gives you, open the options table and run SELECT option_name, option_value FROM wp_options WHERE option_name IN ('users_can_register', 'default_role');. Your table prefix may differ from wp_, but the two option names are the same on every site.

    A value of 1 in users_can_register means the form is open, and subscriber is the safe default. If a value flips back after you change it, something writes it on every request. A plugin or must-use plugin is the usual suspect, so deactivate plugins one at a time until the value stays put.

    Check Whether Anyone Used Your Open Registration

    Fixing the settings closes the door. It does not tell you who already walked through, so check the accounts before you move on. Open Users, then All Users, and use the Administrator and Editor links above the list. Open every account you do not recognize and read its role on the profile screen.

    The database gives a faster view of the newest accounts. Run SELECT ID, user_login, user_registered FROM wp_users ORDER BY user_registered DESC LIMIT 20; to list the twenty most recent sign-ups with their registration time. The user_registered column exists in the core schema, so the query works on every install.

    What to do about an account you did not create

    If an unknown Administrator or Editor exists, treat the site as exposed and work through these steps in order:

    1. Write down the unknown account’s username and registration time before you touch anything.
    2. Change the password of every real Administrator, and use Log Out Everywhere Else on each profile.
    3. Reassign any content the unknown account owns, then delete the account.
    4. Open Plugins and Appearance, Themes and look for anything you did not install, because an Administrator can add both.
    5. Restore from a clean backup if you have one that predates the account.

    Then fix the two options so the same thing cannot happen again. CWE-269, Improper Privilege Management, is the name security teams give to handing an account more access than it needs, and this check is a small, specific guard against it.

    Which Default Roles Trigger the Open Registration With Privileged Default Role Warning

    The role you pick decides what a stranger can do in the first minute. The table below turns the capability grants in WordPress 7.1.3 into plain terms and shows which rows the check flags. It is our reading of the core role definitions for a single-site install.

    Default roleSite Health resultWhat a stranger can do on day oneCapabilities granted by core
    AdministratorCriticalTake over the site: activate and edit plugins, edit themes, change settings, edit other usersactivate_plugins, edit_plugins, edit_themes, edit_users, manage_options
    EditorCriticalPublish and edit any post, upload files, save raw HTMLedit_others_posts, publish_posts, upload_files, unfiltered_html
    AuthorGood (not flagged)Publish and edit their own posts and upload filespublish_posts, edit_published_posts, upload_files
    ContributorGood (not flagged)Write posts and submit them, but not publishedit_posts
    SubscriberGood (not flagged)Read only, and manage their own profileread
    AHosting Default Role Risk Table: which WordPress 7.1.3 default roles the open registration check flags, and what each grants. Source: wp-admin/includes/schema.php, populate_roles_160().

    Read the table from the bottom up. Each step adds a power, and the check draws its line above Author. The line is reasonable for a quick warning, but it is not the line a careful site owner would draw. The role definitions are also documented in the WordPress roles and capabilities guide, which lists the full capability set for every role.

    Why Author and Contributor Pass the Open Registration With Privileged Default Role Check

    The test is a strict comparison against two role names. In code terms it asks whether default_role is in the list editor, administrator, and nothing else. That has two consequences you should know about.

    First, Author passes. A site with Anyone can register on and Author as the default shows a green item, yet every stranger who signs up can publish posts and upload files. Green here does not mean safe.

    Second, custom roles pass. Membership and course plugins create their own role slugs, and the test compares the slug, not the capabilities behind it. A role named member that carries every Editor capability looks identical to a harmless one. Open the plugin that created the role and read what it grants.

    The principle behind both cases is least privilege: give an account only what its job needs. The OWASP Authorization Cheat Sheet puts it as a design rule, and for open sign-ups it reduces to one line. Choose Subscriber unless you have a written reason for anything else.

    What Site Health Cannot Tell You About Open Registration

    The item is a two-value comparison, so it misses several things a careful owner would want to know. It does not look at your existing accounts, so a site that was already abused still shows green once the options are fixed. It does not check whether new sign-ups must confirm an email address or pass any approval step.

    The test also reads only the site-level users_can_register option. On a Multisite network, new-site registration is controlled by a separate network setting that the source reads with get_site_option() in a different file, and this test never looks at it. Treat the item as a prompt to review your sign-up setup, not as a verdict on it.

    Finally, a passed check says nothing about plugins that run their own registration forms. A form from a plugin can create accounts with any role the plugin chooses, whatever your General settings say. If you use such a plugin, read its role setting in the plugin itself.

    When Open Registration Is Intentional: Choosing a Safe Default

    Some sites need public sign-ups: communities, course sites, member areas and shops. The check is not telling you to close registration. It is telling you not to hand out Editor or Administrator while registration is open. For an intentional sign-up form, the safe pattern is short.

    • Leave New User Default Role on Subscriber, so a new account can do nothing but read.
    • Grant any higher role by hand or through a plugin rule you have read, never through the default.
    • Review the newest accounts on a schedule, using the database query above or the Users screen.
    • Read the capabilities of any custom role before you accept it as a default, because the test will not.

    If a membership plugin insists on its own default role, that is a decision about what a stranger should be allowed to do in the first minute. Make it deliberately, with the role table above beside you.

    Check Your Settings for Open Registration With Privileged Default Role

    Pick your two settings below. The checker applies the same logic as the WordPress 7.1.3 test, then adds the verdict the test leaves out for Author, Contributor and custom roles.

    Registration and Default Role Checker

    See AHosting WordPress hosting

    Keep Registration Closed Without Another Plugin

    A fresh WordPress install is safe on both options. The core install defaults set users_can_register to 0 and default_role to subscriber, so every dangerous combination is something that was changed afterward. That is why this item deserves attention even though it takes two minutes to fix.

    If you do run public sign-ups, keep Subscriber as the default and promote people by hand. Our guide to keeping a WordPress site spam-free covers registration controls and server-level blocking.

    Account isolation limits the damage if one site is compromised, as we explain in WordPress hosting security beyond plugins. Two other Site Health items have their own guides: the potentially public log file warning and the auto-update problem check.

    If the Site Health line or the account list still does not make sense, open a ticket with the exact line Site Health printed and the usernames and roles of your Administrator and Editor accounts, with no passwords or email addresses, and we will look at it with you. The WordPress default of Subscriber applies on every plan, from web hosting to a shop on WooCommerce hosting.

    Frequently Asked Questions About Open Registration With Privileged Default Role

    What does open registration with privileged default role mean in WordPress 2026?

    Specifically, it means Anyone can register is switched on while New User Default Role is Editor or Administrator, so every new sign-up becomes a privileged user. WordPress added the check in version 7.0, and the role table above shows exactly which values trip it.

    Is open registration with privileged default role a real risk when Anyone can register is checked?

    Indeed, it is a real risk. The registration form never asks which role a visitor wants, so anyone who can submit it receives the saved default role, unless a plugin adds an approval step of its own. Fixing the default role closes the door, and checking the Users screen shows whether anyone already walked through.

    How do I fix open registration with privileged default role in 2026 if Settings will not save?

    Typically, something rewrites the option on every request, such as a plugin or a must-use plugin. Set default_role to subscriber in the options table, reload Site Health, and if the value flips back, deactivate plugins one at a time until it stays. The code that writes the option is the real problem to remove.

    What are the default user roles in WordPress for new registrations?

    Specifically, a fresh WordPress install leaves Anyone can register off and sets New User Default Role to Subscriber, as the install defaults in core 7.1.3 show. The five built-in roles are Administrator, Editor, Author, Contributor and Subscriber, and only Subscriber is read-only.

    Editor vs Administrator as the default role: which one triggers open registration with privileged default role?

    In fact, both do. The test compares default_role to the two strings editor and administrator and turns critical on either match. Administrator is worse, because that role can edit plugins and themes, while Editor can publish any post and save raw HTML.

    Subscriber vs Contributor in 2026: which default role is safer after open registration with privileged default role is fixed?

    Overall, Subscriber is safer. It holds only the read capability, while Contributor adds edit_posts, which lets every stranger create draft posts inside your admin. Choose Contributor only when you want public submissions and will review each one.

    Who can change the options behind open registration with privileged default role on an AHosting account?

    Notably, only your site’s Administrators, code running inside your site, and anyone with access to your account’s database. The two options live in your own WordPress database, so the warning is a question about your site’s configuration and access, not about the server.

    Can I open a ticket with AHosting about open registration with privileged default role on my site?

    Specifically, yes: send the exact line Site Health printed plus the usernames and roles of your Administrator and Editor accounts, with no passwords or email addresses. We will look at it with you. Fix the two options first if you can, because that takes about two minutes.

    Do AHosting accounts see the same open registration with privileged default role check as any other host?

    Indeed, because the check lives in WordPress core, not in the server. It behaves the same on any host running WordPress 7.0 or later, and the options it reads are stored in your site’s own database wherever it is hosted.

    Why does Site Health 7.1.3 pass an Author default role under open registration with privileged default role?

    In fact, the test only lists editor and administrator, so Author, Contributor and every custom role slug pass. An Author can publish posts and upload files, which makes Author a poor default for open sign-ups even though the item stays green.

    October 16, 2026
  • How to Limit WordPress Post Revisions (2026)

    How to Limit WordPress Post Revisions (2026)

    • Before You Limit WordPress Post Revisions: Where WordPress Stores Them
      • Revisions Live in wp_posts, Not a Separate Table
      • What Triggers a Revision When You Limit WordPress Post Revisions
    • Why You Should Limit WordPress Post Revisions Before the Database Grows
    • What WordPress 7.0 Changed About Revisions, and What It Did Not
      • Visual Revisions Made Revision History Genuinely Useful
      • The Field Guide Documents No Change to Retention or Autosave
    • Three Myths That Make People Limit WordPress Post Revisions Incorrectly
      • Myth 1: The Constant Deletes Revisions You Already Have
      • Myth 2: Every Update Click Creates a New Revision Row
      • Myth 3: OPTIMIZE TABLE Reclaims Your Space Automatically
    • How to Limit WordPress Post Revisions in wp-config.php
      • The Values the Retention Constant Accepts
      • Where the Line Goes, and How to Edit the File Safely
      • Per-Post-Type Limits With the wp_revisions_to_keep Filter
    • Why You Must Clean Up as Well as Limit WordPress Post Revisions
      • The AHosting Revision Cleanup Safety Matrix
      • Running the Cleanup Without Timing Out
    • Choosing a Number: Limit WordPress Post Revisions to Fit How You Edit
    • What the AHosting Stack Changes About Revision Cleanup
      • The Daily Backup Is the Step Most Guides Skip
      • Concurrency: What a Cleanup Costs While It Runs
    • A Practical Checklist: Limit WordPress Post Revisions Safely
    • Frequently Asked Questions About WordPress Post Revisions
      • How do I limit WordPress post revisions in wp-config.php in 2026?
      • Is it true that setting post revisions to a lower number reduces database bloat?
      • WP_POST_REVISIONS vs the wp_revisions_to_keep filter: which should I use to limit WordPress post revisions?
      • How do I remove old post revisions in WordPress without breaking published content?
      • Does the AHosting daily backup protect me if I limit WordPress post revisions incorrectly in 2026?
      • Do WordPress autosaves accumulate in the database the same way post revisions do?
      • Why are my WordPress revisions not showing up in the 7.0 editor?
      • WP-CLI vs raw SQL for revision cleanup: which is safer on shared hosting?
      • Should I limit WordPress post revisions on a WooCommerce store with AHosting WooCommerce hosting?
      • How many entry processes does a bulk cleanup use when I limit WordPress post revisions on AHosting in 2026?
    TL;DR

    Setting WP_POST_REVISIONS caps future growth only. To limit WordPress post revisions and actually shrink the database, you must also delete the rows already stored, because the constant removes none of them.

    If your WordPress database has grown to several times the size of your actual content, stored revisions are the most likely cause. Fortunately, you can limit WordPress post revisions with a single line in wp-config.php. However, that line does something narrower than almost every published guide claims, and understanding the difference is what separates a database that shrinks from one that simply stops growing.

    Listen: why setting WP_POST_REVISIONS caps growth without removing a single stored row. By Matt Chrust, Director of Business Development, AHosting.

    Before You Limit WordPress Post Revisions: Where WordPress Stores Them

    A revision is a complete snapshot of a post saved as its own database row. Specifically, WordPress writes a new row every time a revisioned field changes, so a post edited forty times carries forty child rows alongside the one visible version. Notably, the reason to limit WordPress post revisions is a storage question rather than a performance question at first, and it turns into a performance question only once the row count grows large enough to affect scans, exports, and restores.

    Revisions Live in wp_posts, Not a Separate Table

    Revisions are stored in the same posts table as your published content, distinguished only by their post type value. Consequently, every query that scans that table scans your revision history too, and every database export carries it. In practice, this is why a site with 400 published posts can produce a backup file sized for a site with 12,000. According to the WordPress revisions documentation, revisions are stored in the posts table, and core tracks changes to the title, author, content, and excerpt fields only.

    Therefore the postmeta table is largely unaffected by core revision behavior, which contradicts a common claim. Additionally, plugins that hook into the revision save process can add their own meta rows, so a bloated postmeta table points at a plugin rather than at core.

    What Triggers a Revision When You Limit WordPress Post Revisions

    A revision is written only when one of the tracked fields actually differs from the previous revision. Specifically, core compares the normalized field values before saving and returns early when nothing has changed, a behavior added in version 4.1 and visible in the source of the revision-saving function. As a result, clicking Update ten times without editing anything produces zero new rows.

    This matters because it breaks the arithmetic most guides use. In other words, revision counts track meaningful edits rather than save clicks, so estimating your revision debt from publishing activity alone will overstate it. Ultimately, the only reliable number is the one you measure.

    Why You Should Limit WordPress Post Revisions Before the Database Grows

    Unlimited retention is the default, and nothing in WordPress warns you about it. Specifically, when the constant is left undefined, core treats retention as infinite and keeps every revision a post has ever generated. Consequently, the cost accumulates silently for years, which is why the decision to limit WordPress post revisions is almost always made late.

    The visible symptoms arrive indirectly. For example, nightly backups take longer and consume more storage, database exports during a migration time out, search queries against the posts table slow down, and restore operations that once took two minutes take twenty. Notably, none of these symptoms points at revisions, which is precisely why the cause goes undiagnosed. Our guide on moving a WordPress site to a new host covers why export size is the variable that most often breaks a migration window.

    Importantly, the fix is cheap and the delay is expensive. A site that decides to limit WordPress post revisions in its first month carries almost no debt. By contrast, a five-year-old publication that has never set the constant may hold tens of thousands of rows that now require a deliberate cleanup with its own risks.

    What WordPress 7.0 Changed About Revisions, and What It Did Not

    WordPress 7.0 changed how you read revisions and changed nothing about how many are kept. Specifically, the release shipped Visual Revisions, an in-editor comparison view, while leaving retention, autosave behavior, and storage untouched. Therefore the reason to limit WordPress post revisions is exactly as valid after upgrading as it was before.

    Visual Revisions Made Revision History Genuinely Useful

    Until this release, comparing two versions meant leaving the editor for a separate screen and reading a text diff. In contrast, the WordPress 7.0 Field Guide describes a slider that switches between two versions directly in the editor, a document inspector that summarizes what changed, and color indicators sized to each change that jump to that location when clicked. As a result, revision history moved from a feature most editors ignored to one they will actually open.

    Notably, this reframes the retention decision rather than settling it. In other words, keeping history now buys something real, so the reflexive advice to set retention to two or three and move on deserves more thought than it used to.

    The Field Guide Documents No Change to Retention or Autosave

    The 7.0 Field Guide catalogs more than 419 core tickets and documents Visual Revisions purely as an editor and dashboard change. Importantly, it lists no change to the retention constant, no change to the autosave interval, and no change to how revision rows are written. Consequently, a site that upgraded to 7.0 with unlimited retention still has unlimited retention today.

    One caveat belongs here. Specifically, some managed platforms override the retention constant at the hosting layer, so a value you set in wp-config.php may not be the value in force. Therefore confirm with your host before assuming your configuration file is authoritative. On AHosting, no platform-level override is applied, so the constant behaves exactly as core documents it.

    Three Myths That Make People Limit WordPress Post Revisions Incorrectly

    Each of the three claims below appears in guides that currently rank for this topic, and each is contradicted by core source or by vendor documentation. Notably, each myth leads someone to limit WordPress post revisions in a way that changes nothing, and all three produce the same outcome: a site owner who thinks the problem is solved while the database stays exactly the same size.

    Myth 1: The Constant Deletes Revisions You Already Have

    Defining the retention constant removes nothing. Specifically, pruning happens inside the function that saves a revision, which subtracts your retention number from the current revision count and deletes the excess. That function runs when a post is updated. Consequently, a post you never edit again keeps every revision it has, permanently, no matter what the constant says.

    For example, a site with 800 archived posts averaging 50 revisions each holds 40,000 rows. Setting the constant to five removes zero of them on day one. Ultimately, the number only falls as individual posts are re-saved, which on an archive means never. Therefore capping and cleaning are two separate jobs, and the constant does only the first.

    Myth 2: Every Update Click Creates a New Revision Row

    As covered above, core compares the revisioned fields first and skips the write when nothing changed. In practice, this means the relationship between editorial activity and row count is looser than the estimates published elsewhere suggest. Additionally, it means a workflow with frequent small saves is far less costly than the arithmetic in most guides implies.

    Myth 3: OPTIMIZE TABLE Reclaims Your Space Automatically

    This advice predates the storage engine WordPress actually uses. Specifically, modern WordPress installations run InnoDB, and the MySQL reference manual notes that on InnoDB the statement is implemented as a full table rebuild, with disk space returned to the operating system only when each table has its own tablespace file. By contrast, on a shared system tablespace the space is freed inside the database file and never returns to the filesystem.

    The rebuild also has a cost worth planning around. According to published testing on InnoDB space reclamation, the operation copies the table row by row into a new file, blocks writes for its duration, and needs roughly twice the table size in temporary space. Therefore run it once, after the deletion, and never on a schedule.

    How to Limit WordPress Post Revisions in wp-config.php

    Setting the cap takes one line and one rule about placement. Specifically, to limit WordPress post revisions the constant must be defined before WordPress loads its settings file, which means it belongs above the stop editing comment near the bottom of wp-config.php. Notably, a line added below that comment is read after the constant has already been used and has no effect at all.

    The Values the Retention Constant Accepts

    ValueWhat WordPress doesAutosave behaviorSensible for
    true or -1Stores every revision, forever. This is the default when the constant is undefinedOne autosave per post, per userNothing on shared hosting
    false or 0Stores no revisions at allOne autosave per post is still keptSites with an external version-control workflow
    3Keeps the three most recent revisions per postPlus one autosave per userLow-edit brochure sites
    5Keeps the five most recent revisions per postPlus one autosave per userMost blogs and business sites
    10Keeps the ten most recent revisions per postPlus one autosave per userMulti-author editorial teams
    Values accepted by the WP_POST_REVISIONS constant, per the WordPress revisions documentation.

    Importantly, disabling revisions entirely does not disable autosave. In other words, a value of false still leaves one autosave row per post, which is the row that recovers a browser crash.

    Where the Line Goes, and How to Edit the File Safely

    Edit wp-config.php through the cPanel File Manager rather than over FTP, because the built-in editor keeps a copy you can revert and never introduces line-ending corruption. Additionally, a syntax error in this file takes the whole site down, so add the line, save, and load the site in a second tab before closing the editor. Our walkthrough on editing wp-config.php constants through cPanel covers the exact click path and the recovery step if a save goes wrong.

    Per-Post-Type Limits With the wp_revisions_to_keep Filter

    One number rarely fits every content type on a site. Specifically, the wp_revisions_to_keep filter overrides the constant and receives the post object, so retention can vary by post type, by author, or by any condition you can express in PHP. Furthermore, a post-type-specific variant of the same filter overrides both the constant and the general filter.

    For example, a store that edits product copy weekly and blog posts rarely can keep ten revisions on products and three elsewhere. Therefore the filter is the right tool whenever a single site-wide number would either over-retain the quiet content or under-retain the busy content.

    Why You Must Clean Up as Well as Limit WordPress Post Revisions

    Because the constant is not retroactive, existing rows need a separate deliberate pass. Notably, the four methods available once you limit WordPress post revisions differ in what they remove, not only in how fast they run, and choosing on speed alone is how sites end up with orphaned rows that no cleanup touches afterward.

    The AHosting Revision Cleanup Safety Matrix

    MethodRemoves revision rowsFires WordPress hooksRemoves related orphan rowsMain risk on shared hosting
    Re-saving each post by handOnly the excess above your capYesYesImpractical beyond a few dozen posts
    WP-CLI over SSHYes, all targeted rowsYesYesLong run time on very large sites
    Direct SQL statementYes, all targeted rowsNoNo, leaves orphaned meta and term rowsA mistyped condition deletes published posts
    Cleanup plugin in the browserYes, all targeted rowsYesVaries by pluginRuns inside a web request and can time out mid-pass
    Table rebuild after deletionRemoves nothing furtherNot applicableNot applicableBlocks writes and needs about twice the table size free
    The AHosting Revision Cleanup Safety Matrix: what each cleanup method actually removes and what it leaves behind.

    Read the third row carefully. Specifically, a direct statement is the fastest option and the only one that bypasses WordPress entirely, so nothing cleans up the related rows a proper deletion would remove. Therefore it belongs to people who will follow it with a targeted orphan sweep, not to people who want one command and no follow-up.

    Running the Cleanup Without Timing Out

    A browser-based cleanup runs inside a normal web request, which means it competes with visitor traffic and is subject to the same execution and memory ceilings as any page load. Consequently, on a large site it frequently stops partway with no clear indication of how far it got. Our guide on why raising the memory limit often does not help on shared hosting explains which ceiling actually stops these operations.

    By contrast, a command-line run over SSH is not bound to a web request at all, which is why it is the recommended path on AHosting. Additionally, batching the deletion into chunks of a few hundred rows keeps each statement short and leaves the database responsive for live traffic throughout.

    Choosing a Number: Limit WordPress Post Revisions to Fit How You Edit

    The right retention number is the smallest one that still covers a realistic recovery. Specifically, ask how far back you would ever reach to undo a mistake, then set the cap one step above that. In practice, most site owners answer with one or two edits, which makes three to five the correct range rather than the ten or twenty they were about to choose.

    Notably, Visual Revisions changes this calculation slightly. Because comparing versions is now quick and legible, a multi-author team gains real value from a deeper history than a solo publisher does. Therefore an editorial site with several contributors is the one case where ten is defensible.

    Capping revisions versus cleaning up revisions Two separate jobs: the WP_POST_REVISIONS constant limits revisions created from now on, while existing revision rows are only removed by a deliberate cleanup or by re-saving each post. Two separate jobs, and the constant only does one Setting WP_POST_REVISIONS caps growth. It deletes nothing you already stored. JOB 1 — CAP FUTURE GROWTH define WP_POST_REVISIONS Enforced when a post is next updated Trims the excess above your number Never runs on a post you do not edit Removes 0 rows on day one JOB 2 — CLEAR EXISTING ROWS A deliberate cleanup pass Command line, SQL, or a plugin Run once, from a verified backup Rebuild the table afterward, once This is the step that shrinks the file and AHosting.net | Est. 2002 | Doing only Job 1 is why a database that stopped growing never got smaller.

    Revision Debt Estimator

    Estimate how many revision rows your posts table is already carrying, and what capping retention today would actually remove.

    Estimated revision rows stored now
    0
    See WordPress plans with daily backups

    Estimate only. Rows = posts x meaningful edits per year x years. Capping retention prunes a post only when that post is next updated.

    Read the estimator output as an order of magnitude rather than an exact count. Specifically, it multiplies posts by meaningful edits by years, which is the same arithmetic a database query would confirm in seconds. Ultimately, the number that matters is the gap between what you are storing and what you would ever restore.

    What the AHosting Stack Changes About Revision Cleanup

    Two parts of the hosting environment change how safely a cleanup runs. Specifically, they are the backup that precedes any decision to limit WordPress post revisions and the concurrency budget the cleanup consumes while running.

    The Daily Backup Is the Step Most Guides Skip

    Every AHosting WordPress plan includes a daily backup, which means the prerequisite for a revision cleanup is already in place rather than something you have to arrange first. Importantly, confirm the most recent backup predates your change, because a backup captured after a destructive pass preserves the mistake rather than the content. Restores are handled through a support ticket.

    Additionally, autosave and revision behavior interact with editor traffic in a way worth knowing before you tune anything else. Our measured guide on how the WordPress Heartbeat API drives editor requests covers the autosave interval specifically, which is a separate control from retention and is often confused with it.

    Concurrency: What a Cleanup Costs While It Runs

    AHosting allocates entry processes by plan tier, at 15 on Bronze, 25 on Silver, and 40 on Gold, and a command-line cleanup over SSH occupies one of them for its duration regardless of how many rows it touches. Consequently, running a cleanup during business hours is safe on any tier. By contrast, a browser-based cleanup plugin runs inside a web request, so a long pass competes directly with visitor traffic for the same pool.

    For stores this matters more, because product descriptions are revisioned and edited constantly. Notably, AHosting WooCommerce hosting sets concurrency at the same level as the Silver tier for exactly this reason. Furthermore, agencies running many client sites from one account should read the reseller hosting isolation model before scripting a cleanup across all of them at once.

    Finally, there is a threshold where retention tuning stops being the answer. Specifically, a database large enough that a routine rebuild becomes a scheduling problem has outgrown a shared container, and the honest fix is a VPS with dedicated resources or, at genuine scale, a dedicated server. That said, the overwhelming majority of bloated databases are bloated by revisions alone and need nothing more than the two jobs described here.

    A Practical Checklist: Limit WordPress Post Revisions Safely

    Work through this in order. Notably, the sequence matters more than any individual step, because capping before cleaning leaves rows behind and cleaning before backing up leaves no way out.

    • Confirm the most recent daily backup completed and predates any change you are about to make.
    • Measure what you actually have, so the cleanup can be verified afterward against a real starting number.
    • Set the retention constant in wp-config.php above the stop editing comment, then load the site to confirm no syntax error.
    • Decide whether one number fits every post type, and reach for the filter if it does not.
    • Choose a cleanup method from the Safety Matrix based on what it leaves behind, not on how fast it runs.
    • Run the cleanup from the command line rather than the browser, in batches, so nothing times out mid-pass.
    • Rebuild the table once after the deletion, and understand that space returns to the filesystem only under a per-table tablespace.
    • Re-measure, and confirm the backup file size fell by roughly the amount you expected.

    Ultimately, the goal is not the smallest possible database. In practice, it is a retention setting you chose deliberately, a one-time cleanup that removed the debt accumulated before that decision, and a hosting plan whose backups finish inside their window because the database is the size your content actually justifies.

    Frequently Asked Questions About WordPress Post Revisions

    How do I limit WordPress post revisions in wp-config.php in 2026?

    Specifically, add define( 'WP_POST_REVISIONS', 5 ); above the line that reads stop editing in wp-config.php, then save the file. The constant must be defined before WordPress loads its settings file, so a line placed below that comment is ignored entirely. Importantly, this caps future growth only and deletes nothing that is already stored.

    Is it true that setting post revisions to a lower number reduces database bloat?

    Notably, only for revisions created from that point forward. The cap is enforced inside the function that saves a revision, which runs when a post is updated, so existing rows survive untouched until each affected post is edited again. Therefore an archive of posts you never touch again keeps every revision it already has, forever. The Cleanup Safety Matrix in this post shows which methods actually remove them.

    WP_POST_REVISIONS vs the wp_revisions_to_keep filter: which should I use to limit WordPress post revisions?

    Specifically, use the constant for one site-wide number and the filter when different post types need different retention. The filter overrides the constant, and a post-type-specific variant overrides both. In practice, a store that wants five revisions on products and two on blog posts needs the filter, because a single constant cannot express that.

    How do I remove old post revisions in WordPress without breaking published content?

    Therefore work from a verified backup and delete only rows whose post type is the revision type. A revision row is a child record; removing it never alters the published post, which lives in its own row. However, deleting the parent post by mistake does destroy content, which is why a targeted command that filters on post type is safer than a hand-written query.

    Does the AHosting daily backup protect me if I limit WordPress post revisions incorrectly in 2026?

    Fortunately, yes. Every AHosting WordPress plan includes daily backups, so a cleanup that removes more than intended can be restored. That said, a backup taken after a destructive cleanup is not a safety net, so confirm the most recent backup predates the change before you run anything. Restore requests go through a support ticket.

    Do WordPress autosaves accumulate in the database the same way post revisions do?

    In fact, no. WordPress keeps a single autosave row per post per user and overwrites it rather than adding new rows, and the pruning routine explicitly skips autosave rows when it deletes old revisions. Consequently, autosaves are a fixed, tiny cost while revisions are the unbounded one. Guides that blame autosaves for database growth have the mechanism backwards.

    Why are my WordPress revisions not showing up in the 7.0 editor?

    Typically, the revision panel is empty because retention is switched off, because the post type does not declare revision support, or because fewer than two revisions exist to compare. Additionally, a plugin that adds a metabox to the editor can prevent the new visual comparison from loading. Check the constant first, since a value of false or zero disables storage completely.

    WP-CLI vs raw SQL for revision cleanup: which is safer on shared hosting?

    As such, WP-CLI is safer and raw SQL is faster. WP-CLI routes each deletion through the standard WordPress functions, so hooks fire and related rows are cleaned up properly, while a direct query does not. By contrast, a single statement finishes in seconds where a command loop can run for many minutes and hold a worker the whole time.

    Should I limit WordPress post revisions on a WooCommerce store with AHosting WooCommerce hosting?

    Specifically, yes, because products are a revisioned post type and product descriptions get edited far more often than blog posts. A catalog of two thousand products edited quarterly generates revision rows faster than most content sites do. Notably, orders are unaffected, since modern WooCommerce stores order data outside the posts table entirely.

    How many entry processes does a bulk cleanup use when I limit WordPress post revisions on AHosting in 2026?

    In practice, a command-line cleanup run over SSH consumes one entry process for its duration, not one per row deleted. Because AHosting allocates 15 entry processes on Bronze, 25 on Silver, and 40 on Gold, a single cleanup leaves ample headroom. However, a browser-based cleanup plugin is different, since it runs inside a web request that competes with real visitors.

    August 21, 2026
  • Why Raising the WordPress Memory Limit Doesn’t Work on Shared Hosting (and What Does)

    Why Raising the WordPress Memory Limit Doesn’t Work on Shared Hosting (and What Does)

    TL;DR

    Is your WordPress Memory Limit not working? When your WordPress memory limit is not working after a wp-config.php edit, a second ceiling — the CloudLinux LVE PMEM container cap — is almost always the real blocker on shared hosting, and no configuration file you can edit will change it.

    Editing wp-config.php to fix your WordPress memory limit not working is the advice every guide gives — and it only solves the problem on servers where PHP’s own ceiling is the bottleneck. On shared hosting running CloudLinux — which describes most WordPress hosts in 2026 — there is a third layer above PHP that no WordPress or PHP configuration file can touch. Additionally, that layer is what keeps sending the fatal error even after your edits look correct. Fortunately, this guide explains all three memory ceilings, identifies which one you are actually hitting, and gives you the correct fix path for each.

    Listen: Why your WordPress memory limit edits fail on shared hosting — and what actually fixes it. By Matt Chrust, Director of Business Development, AHosting.

    WordPress Memory Limit Not Working? The Three-Layer Problem

    Is your WordPress Memory Limit not working? Most memory guides treat the problem as a single ceiling to raise. In practice, on shared hosting, three separate memory layers are stacked on top of each other — and a fix that works at one layer may still fail because the ceiling above it has not moved. Notably, this is not a WordPress bug or a configuration error on your part. Your WordPress memory limit not working error is a result of the architecture of modern shared hosting platforms running CloudLinux.

    The Three Memory Layers Behind Every WordPress Server

    WordPress runs PHP, and PHP consumes RAM. However, three separate systems control how much RAM is actually available to your site at any given moment. Understanding which layer is the bottleneck is the prerequisite for choosing the right fix.

    Layer 1 — WP_MEMORY_LIMIT (the WordPress request). WordPress asks PHP to reserve a block of memory at startup. Specifically, the default is 40 MB for a single site and 64 MB for Multisite installations. Adding define('WP_MEMORY_LIMIT', '256M'); to wp-config.php tells WordPress to request 256 MB from PHP — but PHP decides whether to grant it, based on its own ceiling. Refer to the WordPress wp-config.php documentation for the full list of memory constants including WP_MAX_MEMORY_LIMIT for admin-area tasks.

    Layer 2 — PHP memory_limit (the php.ini ceiling). PHP enforces its own per-script memory cap, defined in php.ini or equivalent configuration. If this limit is 128 MB and WordPress requests 256 MB, WordPress receives 128 MB. Consequently, the most reliable way to change this layer on a cPanel host is the MultiPHP INI Editor — not wp-config.php, which only raises the WordPress request and cannot exceed the PHP ceiling.

    Layer 3 — LVE PMEM (the CloudLinux container cap). On servers running CloudLinux OS — the operating system used by most shared WordPress hosts — a third ceiling sits above PHP. The LVE Physical Memory (PMEM) cap limits the total physical RAM the entire hosting account can use at one time, across all PHP processes, cron jobs, and background tasks combined. Importantly, no configuration file you can edit touches PMEM. It is enforced at the OS kernel level and set entirely by your hosting provider on a per-plan basis.

    Why wp-config.php Is a Request, Not an Override

    Adding WP_MEMORY_LIMIT to wp-config.php is frequently the correct first step — and it works when PHP’s ceiling is the actual bottleneck. However, it has two distinct failure modes that most guides do not address.

    First, if PHP’s memory_limit is lower than the value you set in wp-config.php, PHP ignores the request and enforces its own ceiling. Tools › Site Health › Info › Server shows the PHP-enforced value — not what you wrote in wp-config.php — giving the impression that the change had no effect at all.

    Second, even if a wp-config.php edit successfully raises the value WordPress reports in Site Health, the LVE PMEM container cap may still be the bottleneck during peak moments. Specifically, when multiple PHP processes run simultaneously — WooCommerce checkouts, media imports, admin updates, and background cron jobs stacking up — the container runs out of physical RAM and CloudLinux forces a 503. The per-script PHP limit looks fine; the container ceiling is what gives way. For a deeper look at how CloudLinux entry-process limits interact with memory, the companion post on WordPress 503 errors and PHP worker counts explains the relationship in detail. Additionally, WooCommerce hosting plans on AHosting are sized specifically to avoid this pattern at checkout.

    The Hidden Ceiling That Can Cause “WordPress Memory Limit Not Working”: CloudLinux LVE PMEM on Shared Hosting

    What PMEM Is and Why Your WordPress Memory Limit Won’t Budge

    LVE stands for Lightweight Virtual Environment — a kernel-level isolation mechanism built into CloudLinux OS that gives each hosting account its own resource container. PMEM is the physical memory cap within that container. Notably, it operates at a level below anything accessible through the WordPress file system:

    • WordPress reports memory_limit = 512M in Site Health — correct at the PHP layer.
    • PHP attempts to allocate 512 MB for a new script — permitted by the PHP ceiling.
    • However, if the LVE PMEM cap for the account is also 512 MB and two existing PHP processes are each using 200 MB, the new script hits the container wall at 512 MB total — not at its own script limit.

    The result is memory exhausted errors or 503 responses that persist even after a successful php.ini increase. Importantly, this behavior is the direct reason the standard “just edit wp-config.php” advice fails for many shared hosting users — the edit succeeds at the PHP layer, but PMEM is a ceiling that PHP itself cannot see or exceed. This is the same CloudLinux container system that generates 508 Resource Limit Reached errors when entry processes are the bottleneck — a related constraint from the same LVE infrastructure.

    How to Tell Which Ceiling Is Blocking Your WordPress Memory Increase

    Fortunately, diagnosing the specific layer causing your WordPress memory limit not working issue is straightforward using tools already inside your WordPress dashboard.

    Diagnosis step one — check the PHP layer first (after verifying your “WordPress Memory Limit Not Working” status). Go to WordPress dashboard › Tools › Site Health › Info › Server. The “PHP memory limit” line shows the current PHP-enforced ceiling. If this value matches what you set in wp-config.php, Layer 2 is resolved and PMEM may be the next wall.

    Diagnosis step two — if Site Health still shows the old value after a wp-config.php edit, PHP’s own ceiling is still the bottleneck. The cPanel MultiPHP INI Editor is the correct fix at this point — detailed in the fix section below.

    Diagnosis step three — if Site Health shows the correct higher value but errors persist under load, PMEM is the remaining ceiling. At this point, no file you can edit changes the outcome. Furthermore, a temporary phpinfo.php file (containing <?php phpinfo(); ?>, deleted immediately after use) confirms the active memory_limit value PHP is actually enforcing as a cross-check against what Site Health reports.

    The Three-Layer WordPress Memory Stack A stacked diagram showing three memory ceilings on shared hosting. Layer 3 at top: LVE PMEM container cap, set by host, Bronze 512 MB to Gold 2048 MB. Layer 2 in middle: PHP memory_limit in php.ini, default 256 MB, fixable via cPanel INI Editor. Layer 1 at bottom: WP_MEMORY_LIMIT WordPress request, default 40 MB, set in wp-config.php. Layer 3 cannot be changed by editing files. THE THREE-LAYER WORDPRESS MEMORY STACK LAYER 3 — LVE PMEM (CloudLinux Container Cap) Set per plan by host at OS kernel level. Bronze: 512 MB | Silver: 1,024 MB | Gold: 2,048 MB No wp-config.php, php.ini, or .htaccess change can touch this layer. LAYER 2 — PHP memory_limit (php.ini / cPanel INI Editor) Default: 256 MB (PHP 8.4) or 512 MB (PHP 8.3 — selectable via MultiPHP Manager) Self-service fix: cPanel MultiPHP INI Editor. Changes take effect immediately. LAYER 1 — WP_MEMORY_LIMIT (WordPress Request to PHP) Default: 40 MB single site / 64 MB Multisite. Set in wp-config.php. Most guides only address Layer 1. The real ceiling on shared hosting is Layer 3.

    WordPress Memory Limit Not Working: Why Every Common Fix Has a Failure Mode

    Understanding why each common fix has a specific point where it stops working tells you exactly which tool to reach for — and which ones to skip entirely on a LiteSpeed + CloudLinux server. The table below covers every method you are likely to encounter, and its real-world behavior on cPanel shared hosting. Note: object-cache and page-cache memory managed by the LiteSpeed Cache plugin operate independently of the PHP memory_limit configurations covered below.

    Fix MethodLayer It RaisesWorks on LiteSpeed + CloudLinux?Silently Fails WhenVerdict
    WP_MEMORY_LIMIT in wp-config.phpWordPress request onlyYes — if PHP ceiling is already higherPHP memory_limit is equal to or lower than the requested valueFirst step only — not a guaranteed fix
    php_value memory_limit in .htaccessPHP layer (Apache mod_php only)No — LiteSpeed LSAPI and PHP-FPM ignore this directive; can produce 500 errorsServer runs LiteSpeed, Nginx, or PHP-FPMSkip entirely on LiteSpeed hosts
    Custom .user.ini file in site rootPHP layerSometimes — only if host permits user-level INI overridesHost enforces a server-level php.ini that takes priorityHost-dependent — verify with phpinfo()
    cPanel MultiPHP INI EditorPHP layer directlyYes — always on cPanel hostsLVE PMEM cap is still in effect above the PHP layerMost reliable self-service fix
    Plan upgrade (Bronze › Silver › Gold)LVE PMEM container ceilingYes — always; raises the real container ceilingOnly if dedicated memory with no container ceiling is needed (VPS solves this)The real fix when PMEM is the bottleneck

    AHosting’s Memory Architecture by Plan — What Your Limit Can Actually Reach

    Most shared hosts publish their PHP memory limits. AHosting publishes both — the PHP memory_limit and the LVE PMEM container cap per plan — because both matter to understanding why your WordPress memory limit is not working and what will actually fix it. The table below is drawn directly from the AHosting server configuration on sh193, verified June 2026.

    AHosting WordPress Plan Memory Tiers — 2026

    PlanDefault PHP memory_limitLVE PMEM CapPHP Workers (EP)Best Fit
    WP Bronze256 MB (PHP 8.4 default)512 MB15Standard WordPress sites, basic page builders
    WP Silver256 MB (PHP 8.4 default)1,024 MB25Elementor Pro, WooCommerce, multi-plugin builds
    WP Gold256 MB (PHP 8.4 default)2,048 MB40High-traffic, heavy page builders, media-intensive sites

    Note: Switching from PHP 8.4 to PHP 8.3 via cPanel MultiPHP Manager raises the default memory_limit to 512 MB at no additional cost on any plan. All plans allow self-service memory_limit increases via the cPanel MultiPHP INI Editor — up to the plan’s PMEM ceiling. Neither change requires a support ticket.

    Additionally, the default 256 MB memory_limit on PHP 8.4 meets Elementor’s recommended minimum requirement out of the box. For Elementor Pro builds with many widgets and global kits, switching to PHP 8.3 (512 MB default) or using the MultiPHP INI Editor to raise the limit is the recommended approach before a plan upgrade. Full plan details are on the AHosting WordPress hosting page.

    Memory Fix Path Selector

    Answer one question to find your next step.

    After editing wp-config.php, what does Tools › Site Health › Info › Server show as the “PHP memory limit”?

    PHP ceiling is still active.
    wp-config.php raised the WordPress request, but PHP memory_limit is unchanged. Log in to cPanel → Software → MultiPHP INI Editor → select your PHP version → find memory_limit → set to 256M or 512M → Save. Refresh Site Health to confirm the new value.
    PHP layer resolved — but PMEM may still be the ceiling.
    Site Health reflects the new PHP memory_limit. If errors still occur under load (concurrent requests, WooCommerce checkout, media imports), the LVE PMEM container cap is the remaining bottleneck. A plan upgrade from Bronze (512 MB PMEM) to Silver (1,024 MB PMEM) is the correct next step.
    Check first — it takes 30 seconds.
    Go to WordPress dashboard → Tools → Site Health → Info tab → Server section → find “PHP memory limit.” That value tells you exactly which ceiling PHP is enforcing and determines whether wp-config.php or the cPanel MultiPHP INI Editor is your next step.

    What Actually Works: The Correct Fix Path for "WordPress Memory Limit Not Working" Tickets.

    The cPanel MultiPHP INI Editor: The Self-Service Fix Most Guides Skip

    The cPanel MultiPHP INI Editor — found under cPanel › Software › MultiPHP INI Editor — changes php.ini directives per PHP version without requiring a manual php.ini file or .htaccess directives that break under LiteSpeed. Consequently, it is the most reliable self-service fix on cPanel hosts because it modifies the server-side value directly, and what you see in Tools › Site Health afterward is the actual enforced ceiling.

    The process on AHosting is: cPanel › Software › MultiPHP INI Editor › select your PHP version (typically PHP 8.4) › find the memory_limit row › increase the value (256M to 512M is the common first target) › Save. No server restart is required — LiteSpeed applies the change immediately. Importantly, the value you can set here is bounded by your plan’s LVE PMEM cap, so raising the PHP ceiling above PMEM will not give your site more usable memory under concurrent load — the container ceiling is still in effect.

    Confirming Your Memory Limit Change Actually Took Effect

    After any memory change — wp-config.php edit, MultiPHP INI Editor, or plan upgrade — confirm the outcome by checking Tools › Site Health › Info › Server. The “PHP memory limit” row is the ground truth value that PHP is currently enforcing. Additionally, the WordPress server requirements page confirms the recommended minimums: 64 MB absolute minimum, 256 MB recommended for most sites.

    If Site Health shows the new value and memory errors stop, the fix worked at the PHP layer. If Site Health shows the new, correct value and errors still occur under load — specifically during WooCommerce checkouts, large media imports, or simultaneous admin operations — PMEM is still the ceiling.

    When a Plan Upgrade Raises the PMEM Ceiling

    A plan upgrade is the correct fix when the PHP layer is already at the right value — that is, when Site Health shows 256 MB or higher — but memory errors still occur during peak load or when multiple admin tasks run simultaneously. At that point, the PMEM container ceiling is the bottleneck, and only a plan change moves it.

    On AHosting, upgrading from Bronze (512 MB PMEM) to Silver (1,024 MB PMEM) gives Elementor Pro builds, membership sites, and standard WooCommerce stores sufficient container headroom. For high-traffic scenarios where even 1,024 MB PMEM is still the constraint — heavy WooCommerce catalogs, multi-language plugins, large media libraries with concurrent background optimization jobs — Gold (2,048 MB) or a WordPress VPS upgrade removes the shared container ceiling entirely. The guide to signs your WordPress site has outgrown shared hosting covers the full decision checklist for when VPS is the right move.

    Switching Hosts: Why PMEM Transparency Is the Signal

    Finally, most shared hosts publish their PHP memory limits. Very few publish their LVE PMEM container tiers. When a host routes every memory issue through a support queue — rather than a self-service INI editor — and will not disclose the container ceiling, the architecture is the real constraint.

    Specifically, the signal that host transparency is the issue — rather than plan tier — is this pattern: you have raised the PHP memory_limit to the maximum the support team allows, optimized your plugin stack, and memory errors still occur under normal traffic. That pattern means the PMEM ceiling is the bottleneck and the host will not move it within the current plan. Transparent PMEM tiers — published before you buy, self-adjustable via cPanel INI Editor — are the practical test for whether a shared hosting infrastructure will scale with your WordPress site over time.

    WordPress Memory Limit Not Working: A Quick Diagnostic Checklist

    Run through these steps in order before contacting your host or purchasing an upgrade. Furthermore, steps one through three are entirely self-service and take under five minutes on a cPanel host.

    • Open Tools › Site Health › Info › Server and note the current “PHP memory limit” value — this is the PHP-enforced ceiling, not WordPress’s estimate.
    • If the value is below your target: add define('WP_MEMORY_LIMIT', '256M'); to wp-config.php above the “That’s all, stop editing” comment. Refresh Site Health.
    • If Site Health still shows the old value: go to cPanel › Software › MultiPHP INI Editor, select your PHP version, raise memory_limit to 256M or 512M, and save. Refresh Site Health to confirm.
    • If Site Health now shows the correct value but errors persist under load (and you still observe your WordPress Memory Limit not working): the LVE PMEM container cap is the bottleneck. No file edit will help — a plan upgrade is the correct next step.
    • To raise the PMEM ceiling on AHosting: upgrade from Bronze (512 MB PMEM) to Silver (1,024 MB PMEM), or to Gold (2,048 MB PMEM) for the highest shared-hosting tier.
    • After any change: confirm with a fresh Site Health check. For the highest certainty, create a temporary phpinfo.php file in your site root, verify the memory_limit row, and delete the file immediately.

    Additionally, the companion post on WordPress memory limit errors and why wp-config changes often fail covers the full range of error messages and diagnosis paths in more detail.

    Frequently Asked Questions: WordPress Memory Limit Not Working on Shared Hosting

    Why does my WordPress memory limit not change after editing wp-config.php on shared hosting in 2026?

    Typically, this happens because WP_MEMORY_LIMIT in wp-config.php is a request to PHP, not an override. WordPress asks PHP to allocate more memory, but PHP can only honor the request up to its own php.ini ceiling — and on CloudLinux shared hosting, there is a third ceiling above that called the LVE PMEM cap. If the php.ini ceiling or the PMEM cap is lower than what you requested, the change appears to fail silently. The fix depends on which ceiling you are actually hitting, which the cPanel MultiPHP INI Editor and the AHosting plan tier table above help identify.

    What is the three-layer WordPress memory stack, and which layer is impossible to raise by editing files alone?

    Specifically, the three layers are: WP_MEMORY_LIMIT (what WordPress requests from PHP), PHP memory_limit (the PHP ceiling in php.ini), and the LVE PMEM cap (the CloudLinux kernel-level container ceiling). The third layer — LVE PMEM — cannot be raised by editing any WordPress or PHP configuration file. It is set at the operating system level by CloudLinux and is controlled entirely by the hosting provider, either through a cPanel account setting or by upgrading to a higher plan tier.

    WordPress memory_limit in wp-config.php vs. LVE PMEM — which one is the real ceiling on CloudLinux shared hosting?

    Notably, LVE PMEM is the real ceiling on CloudLinux shared hosting. PHP memory_limit controls how much memory a single PHP script can request — but LVE PMEM caps the total physical memory the entire hosting account can use at once. A wp-config.php change raises the WordPress request layer and can help when PHP memory_limit is the bottleneck, but it cannot affect LVE PMEM. On AHosting plans, the PMEM ceiling ranges from 512 MB on Bronze to 2,048 MB on Gold — see the AHosting WordPress Plan Memory Tiers table above.

    WordPress Memory Limit Not Working Tickets: When should I use the cPanel MultiPHP INI Editor instead of wp-config.php to fix a WordPress memory limit issue?

    The cPanel MultiPHP INI Editor is the right tool when wp-config.php appears to change nothing — that is, when Tools › Site Health still shows the old memory limit after you added the WP_MEMORY_LIMIT constant. The MultiPHP INI Editor raises the PHP layer directly, without going through WordPress. It is the most reliable self-service fix on cPanel hosts like AHosting, and changes take effect immediately without restarting the server.

    What is LVE PMEM and why does it override php.ini memory settings on CloudLinux shared hosting?

    Essentially, LVE PMEM (Physical Memory) is the CloudLinux kernel-level cap on the total physical RAM a hosting account can allocate at any one time. It is enforced at the operating system layer — above PHP, above WordPress, and above any configuration file a site owner can edit. Because PMEM is a container ceiling rather than a per-script limit, it applies to the combined memory of every PHP process, cron job, and background task running in the account simultaneously. When an account’s combined usage hits PMEM, additional PHP processes receive a 503 error regardless of what php.ini says.

    WordPress Silver vs. Bronze plan at AHosting — how much PMEM headroom does each give for memory-intensive plugins and how does this fix my WordPress Memory Limit not working?

    Specifically, AHosting Bronze provides a 512 MB PMEM ceiling and 256 MB default PHP memory_limit — appropriate for standard WordPress sites and basic Elementor builds. Silver doubles the PMEM to 1,024 MB, giving Elementor Pro, WooCommerce stores, and multi-plugin setups genuine headroom without hitting the container ceiling during peak load. Gold raises PMEM to 2,048 MB, designed for high-traffic or highly customized WordPress installations. All plan details and upgrade options are available on the AHosting WordPress hosting page.

    When does increasing the PHP memory limit in WordPress fail to fix the error on LiteSpeed shared hosting in 2026?

    Unfortunately, increasing the PHP memory limit fails to fix memory exhausted errors on LiteSpeed shared hosting in 2026 when the LVE PMEM container cap is the actual ceiling — not PHP memory_limit - meaning this won't address your WordPress memory limit not working issue. This happens most often on Bronze-tier plans running Elementor Pro, WooCommerce with heavy extensions, or multiple concurrent admin tasks. In those scenarios, the PHP limit may read 512 MB in Site Health, but the container runs out of PMEM before any individual PHP script hits that limit. The solution is either a plan upgrade or offloading background tasks to reduce peak concurrent memory usage.

    How do I confirm a WordPress memory limit fix actually took effect on my AHosting cPanel account in 2026?

    If you previously found your WordPress memory limit not working, the most reliable confirmation method is WordPress Tools › Site Health › Info › Server — the “PHP memory limit” line there reflects the active server-side value, not just what WordPress requested in wp-config.php. If the value still shows 256 MB after a wp-config.php change, the PHP layer is the ceiling and the cPanel MultiPHP INI Editor is the correct next step. AHosting customers can also create a temporary phpinfo.php file in their site root and check the memory_limit row to see the value PHP is actually enforcing, then delete the file after confirming.

    What PHP memory limit does AHosting set by default in 2026, and what is the PMEM ceiling on each plan?

    Currently, AHosting WordPress accounts default to PHP 8.4 with a 256 MB memory_limit — meeting Elementor’s recommended minimum out of the box. PHP 8.3 accounts receive 512 MB by default. On the PMEM side, Bronze plans cap the container at 512 MB, Silver at 1,024 MB, and Gold at 2,048 MB. Customers can raise the PHP memory_limit via the cPanel MultiPHP INI Editor without opening a support ticket, up to the plan’s PMEM ceiling.

    Does shared hosting cause WordPress memory limit errors more frequently than VPS or managed WordPress hosting?

    Generally, yes — shared hosting generates WordPress memory limit errors more often because every account shares a server’s physical RAM within fixed LVE PMEM containers, rather than having dedicated memory allocation. On VPS or managed WordPress hosting, memory limits are either higher by default or configurable without container constraints. That said, shared hosting is appropriate for most WordPress sites when the plan tier’s PMEM ceiling matches the site’s actual load — the key is matching memory tiers to site requirements rather than assuming shared hosting cannot scale.

    June 29, 2026
1 2
Next Page→
Ahosting Logo

Hosting

  • WordPress Hosting
  • Web Hosting
  • FFmpeg Hosting
  • WooCommerce Hosting
  • Reseller Hosting
  • VPS Hosting
  • Dedicated Server

Domain

  • Register a Domain
  • Domain Transfer
  • Premium SSL Certificate

Support

  • Knowledge Base
  • Abuse Report
  • Submit A Ticket

Company

  • Compare Hosts
  • About Us
  • Datacenter
  • Contact Us
  • Blog
  • Sitemap

Legal

  • Privacy Policy
  • Terms of Service
  • Acceptable Use Policy
  • Service Level Agreement
  • Resource Abuse Policy
  • Hosting
    • WordPress Hosting
    • Web Hosting
    • FFMpeg Hosting
    • WooCommerce Hosting
    • Reseller Hosting
    • VPS Hosting
    • Dedicated Server
  • Domain
    • Register a Domain
    • Domain Transfer
    • Premium SSL Certificate
  • Support
    • Knowledge Base
    • Abuse Report
    • Submit A Ticket
  • Company
    • About Us
    • Datacenter
    • Contact Us
    • Blog
    • Sitemap
  • Legal
    • Privacy Policy
    • Terms of Service
    • Acceptable Use Policy
    • Service Level Agreement
    • Resource Abuse Policy

Copyright © 2026 All Rights Reserved

Ahosting, Inc. BBB Accredited Business, A+ rating
Facebook X/Twitter Instagram LinkedIn YouTube