404 Not Found on Posts and Pages
Symptoms
You click a post link and get a 404 page — but the post is right there in your dashboard, published and everything. This is one of the most common WordPress issues, and nine times out of ten it’s a permalink rewrite problem, not a missing page. The right way to fix this is to work through the causes methodically instead of randomly toggling settings.
What Causes 404 Not Found on Posts and Pages?
- Corrupted
.htaccessfile — WordPress writes rewrite rules to.htaccess(on Apache). If this file gets corrupted, deleted, or has wrong permissions, every URL except the homepage breaks. - Permalink settings out of sync — A plugin, theme switch, or manual database edit can desync the permalink structure WordPress expects from what’s actually written to the server config.
- Missing
mod_rewriteon Apache — Your server needsmod_rewriteenabled for pretty permalinks to work. Some cheap hosts disable it by default. - Nginx missing rewrite rules — If you’re on Nginx, there’s no
.htaccess. The rewrite rules live in your server block config, and they’re often missing after a migration. - Custom post type
rewriteflush needed — If a plugin registers a custom post type and the rewrite rules haven’t been flushed, those URLs 404 immediately.
How to Fix It
Step 1: Flush Permalink Rules from the Dashboard
This fixes the problem about 70% of the time. Go to Settings → Permalinks in your WordPress admin. Don’t change anything — just click Save Changes. This forces WordPress to regenerate its rewrite rules.
If you can’t access the admin, use WP-CLI over SSH:
wp rewrite flush
Check your site. If posts load now, you’re done. If not, keep going.
Step 2: Check and Reset .htaccess
Connect to your site via FTP or SSH and open the .htaccess file in your WordPress root directory (same level as wp-config.php).
The file should contain this block for a standard WordPress install:
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule. /index.php [L]
</IfModule>
# END WordPress
If the file is empty, missing, or full of garbage, replace its contents with the block above. If the file doesn’t exist, create it. Then set permissions:
chmod 644.htaccess
If WordPress can’t write to .htaccess (you’ll see a notice in the Permalinks screen), temporarily set chmod 666, save permalinks, then set it back to 644.
Step 3: Verify mod_rewrite Is Enabled
SSH into your server and check:
apache2ctl -M | grep rewrite
You should see rewrite_module. If not, enable it:
sudo a2enmod rewrite
sudo systemctl restart apache2
On Nginx, there’s no mod_rewrite. Instead, confirm your server block includes the WordPress rewrite rule:
location / {
try_files $uri $uri/ /index.php?$args;
}
Reload Nginx after any changes:
sudo nginx -t && sudo systemctl reload nginx
Step 4: Enable Debug Mode to Check for Plugin Conflicts
If flushing rewrites didn’t help, a plugin might be interfering with URL routing. Add this to wp-config.php (before the “stop editing” comment):
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
Then deactivate all plugins at once:
wp plugin deactivate --all
Check your site. If the 404s are gone, reactivate plugins one by one to find the culprit:
wp plugin activate plugin-name
Test after each activation. The plugin that brings back the 404 is your problem. Update it, replace it, or contact the developer.
Step 5: Check for Custom Post Type Rewrite Issues
If only custom post type URLs are 404ing (like /portfolio/ or /products/), the rewrite rules for that post type haven’t been registered. This happens after activating a new plugin or theme that registers custom post types.
Flush rewrites with the --hard flag:
wp rewrite flush --hard
This regenerates both the internal rewrite rules and the .htaccess file. If you’re building a custom plugin that registers post types, skip this if you want headaches later — always hook flush_rewrite_rules on plugin activation:
register_activation_hook( __FILE__, function() {
your_register_post_types_function();
flush_rewrite_rules();
});
Step 6: Check Your WordPress Address and Site Address
Go to Settings → General (or check wp-config.php) and make sure WordPress Address (URL) and Site Address (URL) match and use the correct protocol. A mismatch between http and https or www and non-www causes routing failures.
You can force these in wp-config.php:
define( 'WP_HOME', 'https://yourdomain.com' );
define( 'WP_SITEURL', 'https://yourdomain.com' );
Prevention
- Never manually edit
.htaccessunless you know exactly what you’re adding. Always back it up first. - Flush permalinks after any plugin or theme change that registers custom post types or taxonomies. A quick trip to Settings → Permalinks → Save costs you five seconds and prevents hours of debugging.
- Use WP-CLI in your deployment workflow. Add
wp rewrite flushto your deploy script so rewrites regenerate automatically after every release. - Keep a backup of your working
.htaccessin version control or your server backup system. When things break, you can restore it in seconds instead of troubleshooting from scratch.
Last verified: April 2026