How to Fix “The Link You Followed Has Expired” Error in WordPress
The "The link you followed has expired" error in WordPress is triggered when a file upload or form submission exceeds one or more PHP runtime limits — specifically upload_max_filesize, post_max_size, max_execution_time, or memory_limit. WordPress cannot gracefully recover from these server-side rejections, so it surfaces this generic message instead of a specific PHP error.
The fix requires raising those PHP directive values through whichever configuration layer your hosting environment exposes: php.ini, .htaccess, wp-config.php, or a control panel UI. Which method works depends entirely on your server access level — root SSH access, managed cPanel, or a locked-down shared environment each require a different approach.
Why This Error Actually Occurs
Understanding the root cause prevents you from applying the wrong fix. When WordPress processes an upload, the browser sends a multipart POST request to wp-admin/async-upload.php or wp-admin/update.php. PHP evaluates the request against four independent limits before WordPress ever executes a single line of application code:
upload_max_filesize— hard ceiling on any single uploaded filepost_max_size— ceiling on the entire POST body, which must be *larger* thanupload_max_filesizemax_execution_time— maximum wall-clock seconds a PHP process may runmemory_limit— RAM available to the PHP process; image processing and theme installation are memory-intensive
If any one of these is breached, PHP silently terminates the request. WordPress receives an empty or malformed response and displays "The link you followed has expired." The error is not a WordPress bug — it is PHP enforcing server policy.
Common triggers in practice:
- Installing a premium theme (often 5–30 MB) on a shared host with a 2 MB default upload limit
- Uploading a WooCommerce product CSV import file
- Installing a plugin bundle that includes bundled assets
- Restoring a site from a backup archive through the WordPress dashboard
- Running a long-running import script that hits the execution time ceiling
PHP Directive Quick-Reference Table
| Directive | Default (typical shared host) | Recommended minimum | What it controls |
|---|---|---|---|
| — | — | — | — |
| `upload_max_filesize` | 2M | 64M–128M | Maximum size of a single uploaded file |
| `post_max_size` | 8M | 128M (must exceed upload limit) | Maximum size of the entire POST request body |
| `max_execution_time` | 30 | 300 | Seconds before PHP kills the script |
| `max_input_time` | 60 | 300 | Seconds PHP spends parsing input data |
| `memory_limit` | 128M | 256M | RAM per PHP process |
Critical rule: post_max_size must always be set higher than upload_max_filesize. If you set upload_max_filesize = 128M but leave post_max_size = 8M, uploads will still fail because the POST body limit is hit first.
Method 1: Edit php.ini (Recommended for VPS and Dedicated Servers)
This is the most reliable and permanent method. On a VPS Hosting or Dedicated Server environment where you have root or sudo access, you control the PHP configuration directly.
Locate the active php.ini file:
php --ini | grep "Loaded Configuration File"Or from within a WordPress site, create a temporary file:
<?php phpinfo(); ?>Look for the Loaded Configuration File row in the output, then delete the file immediately after.
Edit the directives:
upload_max_filesize = 128M
post_max_size = 256M
max_execution_time = 300
max_input_time = 300
memory_limit = 256MAfter saving, restart PHP-FPM or Apache to apply the changes:
# For PHP-FPM (most common on modern stacks)
sudo systemctl restart php8.2-fpm
# For Apache with mod_php
sudo systemctl restart apache2
# For Nginx + PHP-FPM
sudo systemctl restart nginx php8.2-fpmVerify the new values took effect:
php -r "echo ini_get('upload_max_filesize');"Edge case to know: On servers running multiple PHP versions (a common setup on cPanel), there is a separate php.ini for each version. Editing the wrong one has no effect. Confirm which PHP version WordPress is using before editing.
Method 2: Use .htaccess (Apache Shared Hosting)
If you are on shared hosting without direct php.ini access, and your server runs Apache with mod_php or suPHP, you can override PHP directives per-directory using .htaccess.
Access your WordPress root directory via FTP, SFTP, or your hosting file manager. Open .htaccess and append the following block:
<IfModule mod_php.c>
php_value upload_max_filesize 128M
php_value post_max_size 256M
php_value max_execution_time 300
php_value max_input_time 300
php_value memory_limit 256M
</IfModule>Save and upload the file, then test your upload.
Important caveats:
- This method does not work on servers running PHP-FPM, CGI, or FastCGI. On those stacks,
php_valuedirectives in.htaccesswill cause a 500 Internal Server Error because the Apache module handling PHP is notmod_php. If you see a 500 after saving, remove those lines immediately. - On Nginx servers,
.htaccessis ignored entirely. Usephp.inior aphp.iniuser override file instead. - Some managed hosts explicitly disable
AllowOverridefor PHP directives, making this method ineffective even on Apache.
Method 3: Add Directives to wp-config.php
This method uses PHP's ini_set() function to override directives at runtime. It works regardless of the web server type, but it is subject to the host's open_basedir and disable_functions restrictions — some hosts block ini_set() for security reasons.
Open wp-config.php in your WordPress root and add the following lines before the /* That's all, stop editing! Happy publishing. */ comment:
@ini_set( 'upload_max_size', '128M' );
@ini_set( 'post_max_size', '256M' );
@ini_set( 'max_execution_time', '300' );
@ini_set( 'max_input_time', '300' );
@ini_set( 'memory_limit', '256M' );The @ suppresses errors if ini_set() is disabled, preventing a white screen. However, if the host has locked these values at the server level using php_admin_value, ini_set() calls are silently ignored — the values will not change.
How to verify it actually worked:
Install the free Query Monitor plugin and check the PHP environment tab, or add a temporary phpinfo() call. If the values still show the old limits, ini_set() is being overridden at a higher level and you need to use a different method.
Method 4: Adjust PHP Settings in cPanel
For hosting environments managed through cPanel — including VPS with cPanel — you can modify PHP limits through the graphical interface without touching any files.
Steps:
- Log in to cPanel.
- Navigate to Software and click MultiPHP INI Editor.
- Select the document root of your WordPress site from the dropdown.
- Locate and update the following fields:
upload_max_filesize→128Mpost_max_size→256Mmax_execution_time→300memory_limit→256M
- Click Apply.
Alternatively, use Select PHP Version (PHP Selector) if your host uses CloudLinux. Under the Options tab, the same directives are available as sliders or input fields.
What cPanel actually does behind the scenes: It writes a .user.ini file (for PHP-FPM) or modifies .htaccess (for mod_php) in your document root. If you later manually edit those files, you may overwrite cPanel's changes — be aware of this conflict.
Method 5: Create or Edit a .user.ini File (PHP-FPM Environments)
This is the method most tutorials omit, yet it is the correct approach for PHP-FPM — which is the default PHP handler on virtually every modern hosting stack, including Nginx-based environments.
Create a file named .user.ini in your WordPress root directory with the following content:
upload_max_filesize = 128M
post_max_size = 256M
max_execution_time = 300
max_input_time = 300
memory_limit = 256MUpload it to the same directory as wp-config.php. PHP-FPM scans for .user.ini files periodically — the cache TTL is controlled by user_ini.cache_ttl, which defaults to 300 seconds (5 minutes). Changes are not instantaneous. If you need immediate effect, restart PHP-FPM.
sudo systemctl restart php8.2-fpmSecurity note: The .user.ini file should not be web-accessible. Add this to your .htaccess if you are on Apache:
<Files ".user.ini">
Require all denied
</Files>On Nginx, add a location block to deny access:
location ~ /.user.ini {
deny all;
}Method 6: Contact Your Hosting Provider
If none of the above methods produce a change in the PHP values you verified with phpinfo() or Query Monitor, the host is enforcing limits at the PHP-FPM pool level or via php_admin_value directives in the server configuration — both of which cannot be overridden by any user-accessible file.
In this case, contact support and request specific increases. Provide the exact directive names and target values. If the host refuses or imposes a hard ceiling that does not meet your requirements, consider migrating to a VPS Hosting plan where you control the PHP configuration entirely.
Diagnosing Which Limit Is Actually Triggering the Error
Rather than guessing, use these diagnostic steps before applying any fix:
Check current PHP limits from the command line:
php -r "echo 'upload_max_filesize: ' . ini_get('upload_max_filesize') . PHP_EOL;
echo 'post_max_size: ' . ini_get('post_max_size') . PHP_EOL;
echo 'max_execution_time: ' . ini_get('max_execution_time') . PHP_EOL;
echo 'memory_limit: ' . ini_get('memory_limit') . PHP_EOL;"Check the PHP error log for the actual failure:
tail -n 50 /var/log/php/error.log
# or
tail -n 50 /var/log/apache2/error.logLook for lines containing Allowed memory size, Maximum execution time, or POST Content-Length. The specific message tells you exactly which directive to target.
Check the size of the file you are uploading against the current upload_max_filesize. If the file is 45 MB and the limit is 64 MB, the upload limit is not the problem — look at post_max_size or memory_limit instead.
Choosing the Right Method: Decision Matrix
| Your environment | Recommended method |
|---|---|
| — | — |
| VPS or dedicated server with root SSH | Edit system `php.ini`, restart PHP-FPM |
| cPanel shared hosting | MultiPHP INI Editor or PHP Selector |
| Apache shared hosting, no cPanel | `.htaccess` with `php_value` (mod_php only) |
| Nginx + PHP-FPM, no root access | `.user.ini` in WordPress root |
| Any environment, quick test | `wp-config.php` with `ini_set()` |
| All methods fail | Contact host or migrate to VPS |
Key Technical Checklist Before Considering This Resolved
post_max_sizeis set higher thanupload_max_filesize— this is the most common misconfiguration- Changes have been verified with
phpinfo()orphp -r "echo ini_get(...)"— not just assumed - PHP-FPM was restarted if
.user.iniorphp.iniwas edited directly - The
.user.iniorphp.inibeing edited matches the PHP version actually serving the WordPress site memory_limitis at least 256M if you are installing large themes or running image-heavy operations- The error log was checked to confirm which specific limit caused the termination
- If on a Shared Web Hosting plan, the host's hard ceiling has been confirmed — some providers cap
upload_max_filesizeat 64M regardless of user settings - After fixing the upload error, verify your SSL Certificates are valid if you are accessing wp-admin over HTTPS, as mixed-content or certificate errors can produce superficially similar redirect failures
FAQ
Why does the error appear even after I increased upload_max_filesize in .htaccess?
The server is likely running PHP via FastCGI or PHP-FPM rather than mod_php. The php_value directive in .htaccess is only processed by Apache's mod_php handler. On PHP-FPM stacks, use a .user.ini file in the WordPress root directory instead.
What is the difference between upload_max_filesize and post_max_size, and why do both matter?
upload_max_filesize limits the size of each individual file in a multipart upload. post_max_size limits the total size of the entire POST request body, which includes the file data plus form fields and boundaries. If post_max_size is smaller than upload_max_filesize, the POST body limit is hit first and PHP discards the entire request before WordPress can evaluate the file size.
My ini_set() calls in wp-config.php are being ignored. Why?
The host is using php_admin_value in the PHP-FPM pool configuration or the Apache virtual host block. php_admin_value sets a directive as read-only from the application's perspective — ini_set() calls for those directives are silently discarded. Only the hosting provider can change values set this way.
How do I verify that my PHP configuration changes actually took effect?
Create a temporary file in your WordPress root containing <?php phpinfo(); ?>, access it in a browser, and search for the directive name. The Local Value column shows the effective value for that directory. Delete the file immediately after checking — leaving phpinfo() output publicly accessible is a security risk.
Can this error be caused by something other than PHP upload limits?
Yes. A WordPress nonce expiration can produce the same message. WordPress nonces are valid for 24 hours by default. If a user opens the plugin upload page, leaves it idle for over 24 hours, and then submits the form, the nonce validation fails and WordPress displays "The link you followed has expired." In this case, simply refreshing the page generates a new nonce and the upload proceeds normally — no PHP configuration changes are needed.
