# Fix WordPress Permalink 404 Error

You've set your permalinks to "Post name" or another pretty permalink structure, but clicking any link returns a 404 Not Found error. The homepage works fine, but every inner page is broken. This is almost always a rewrite rules or .htaccess issue.

Pretty permalinks rely on URL rewriting. Apache uses mod_rewrite via .htaccess, and Nginx uses try_files directives. When rewriting fails, WordPress never receives the request, and the server returns 404.

Introduction

This article covers troubleshooting steps and solutions for Fix WordPress Permalink 404 Error. The error typically occurs in production environments and can cause service disruptions if not addressed promptly.

Symptoms

Common error messages include:

```bash # Check if permalinks are set correctly wp option get permalink_structure

# Test a post URL wp eval 'echo get_permalink(1) . "\n";'

# Check if .htaccess exists ls -la .htaccess

# Check Apache modules apache2ctl -M | grep rewrite ```

```bash # Flush rewrite rules wp rewrite flush --hard

# Verify .htaccess was regenerated cat .htaccess ```

```bash # Create or overwrite .htaccess cat > .htaccess << 'EOF' # BEGIN WordPress RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress EOF

# Set correct permissions chmod 644 .htaccess chown www-data:www-data .htaccess ```

Common Causes

  • Configuration misconfiguration
  • Missing or incorrect credentials
  • Network connectivity issues
  • Version compatibility problems
  • Resource exhaustion or limits
  • Permission or access denied

Step-by-Step Fix

```bash # Check if permalinks are set correctly wp option get permalink_structure

# Test a post URL wp eval 'echo get_permalink(1) . "\n";'

# Check if .htaccess exists ls -la .htaccess

# Check Apache modules apache2ctl -M | grep rewrite ```

Fix 1: Regenerate .htaccess

The most common fix is regenerating the .htaccess file.

Via WordPress Admin

  1. 1.Go to Settings > Permalinks
  2. 2.Don't change anything
  3. 3.Click "Save Changes"

This regenerates .htaccess with correct rewrite rules.

Via WP-CLI

```bash # Flush rewrite rules wp rewrite flush --hard

# Verify .htaccess was regenerated cat .htaccess ```

Manually Create .htaccess

If WordPress can't write to .htaccess:

```bash # Create or overwrite .htaccess cat > .htaccess << 'EOF' # BEGIN WordPress RewriteEngine On RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] # END WordPress EOF

# Set correct permissions chmod 644 .htaccess chown www-data:www-data .htaccess ```

For Subdirectory Install

If WordPress is in a subdirectory:

apache
# BEGIN WordPress
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /subdirectory/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdirectory/index.php [L]
# END WordPress

Fix 2: Enable Apache mod_rewrite

If .htaccess is correct but permalinks still fail:

```bash # Check if mod_rewrite is enabled apache2ctl -M | grep rewrite

# Enable mod_rewrite (Debian/Ubuntu) sudo a2enmod rewrite sudo systemctl restart apache2

# Enable mod_rewrite (CentOS/RHEL) # mod_rewrite is enabled by default, but check: httpd -M | grep rewrite ```

Fix 3: AllowOverride Configuration

Apache needs to allow .htaccess overrides.

Check your Apache configuration:

```bash # Find Apache config files apache2ctl -S | grep "config file"

# Check virtual host configuration # Look for AllowOverride None and change to AllowOverride All ```

Edit your Apache site configuration:

apache
<Directory /var/www/html>
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
</Directory>

Then restart Apache:

bash
sudo systemctl restart apache2
# or
sudo systemctl restart httpd

Fix 4: Nginx Configuration

Nginx doesn't use .htaccess. You need proper try_files in your server block.

```nginx server { listen 80; server_name yourdomain.com; root /var/www/html; index index.php;

location / { try_files $uri $uri/ /index.php?$args; }

location ~ \.php$ { fastcgi_pass unix:/run/php/php8.1-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } ```

Test and reload:

```bash # Test Nginx config nginx -t

# Reload Nginx sudo systemctl reload nginx ```

Nginx Multisite Configuration

For WordPress Multisite with subdirectories:

```nginx location / { try_files $uri $uri/ /index.php?$args; }

# Handle uploaded files location ~ ^/files/(.+)$ { try_files /wp-content/blogs.dir/$blogid/$uri /wp-includes/ms-files.php?file=$1; } ```

For subdomain multisite:

```nginx server { server_name yourdomain.com *.yourdomain.com; root /var/www/html;

location / { try_files $uri $uri/ /index.php?$args; } } ```

Fix 5: File Permissions

WordPress needs write access to create/update .htaccess:

```bash # Check current permissions ls -la .htaccess ls -la .

# Fix permissions chmod 644 .htaccess chown www-data:www-data .htaccess

# WordPress directory should be writable chmod 755 . chown www-data:www-data . ```

Fix 6: Database Rewrite Rules

Sometimes rewrite rules are corrupted in the database:

```bash # Check rewrite rules in database wp option get rewrite_rules

# Flush rewrite rules wp rewrite flush

# Or delete and regenerate wp option delete rewrite_rules wp rewrite flush ```

Fix 7: Check for Conflicting .htaccess

Multiple .htaccess files or conflicting rules cause issues:

```bash # Check for .htaccess in parent directories ls -la ../.htaccess

# Check for multiple .htaccess find . -name ".htaccess"

# Look for conflicting rules grep -r "RewriteRule|RewriteCond" .htaccess ```

Common conflicts:

  • Redirect rules before WordPress rules
  • Rules from security plugins that block requests
  • Hotlink protection rules

Fix 8: Custom Post Type 404s

If regular pages work but custom post types return 404:

```bash # Flush rewrite rules for custom post types wp rewrite flush

# Check if custom post type is registered wp eval ' $post_types = get_post_types(array("_builtin" => false), "names"); print_r($_post_types); '

# Check rewrite rules for CPT wp eval ' global $wp_rewrite; $rules = $wp_rewrite->rewrite_rules(); print_r(array_filter($rules, function($k) { return strpos($k, "your-cpt") !== false; }, ARRAY_FILTER_USE_KEY)); ' ```

The custom post type needs rewrite => true and flush_rewrite_rules on activation:

```php register_post_type('your-cpt', array( 'rewrite' => array('slug' => 'your-cpt'), // other args ));

// Flush on plugin activation register_activation_hook(__FILE__, 'flush_rewrite_rules'); ```

Debug Rewrite Rules

```bash # List all rewrite rules wp eval ' global $wp_rewrite; echo "Permalink structure: " . $wp_rewrite->permalink_structure . "\n"; echo "Rewrite rules:\n"; print_r($wp_rewrite->rewrite_rules()); '

# Match a URL against rules wp eval ' global $wp_rewrite; $url = "/your-post-slug/"; $match = $wp_rewrite->match($url); print_r($match); ' ```

Debug .htaccess Processing

Add to .htaccess for debugging:

apache
RewriteEngine On
RewriteLog "/var/log/apache2/rewrite.log"
RewriteLogLevel 5

Then test a URL and check the log:

bash
tail -f /var/log/apache2/rewrite.log

Check for URL Conflicts

```bash # Test if actual file/directory exists ls -la /var/www/html/your-post-slug/

# Check for conflicting files find . -name "*.html" -o -name "*.php" | grep -v wp- ```

Verification

After applying fixes:

```bash # Test homepage curl -I https://yourdomain.com/ # Should return 200 OK

# Test a post curl -I https://yourdomain.com/sample-post/ # Should return 200 OK, not 404

# Test a page curl -I https://yourdomain.com/sample-page/ # Should return 200 OK

# Test category archive curl -I https://yourdomain.com/category/uncategorized/ # Should return 200 OK ```

Common Scenarios

After Migration

If 404s appear after migrating to a new server:

```bash # Regenerate .htaccess wp rewrite flush --hard

# Check Apache modules apache2ctl -M

# Check file permissions ls -la .htaccess ```

After Changing Permalink Structure

```bash # Change structure wp rewrite structure '/%postname%/'

# Flush rules wp rewrite flush --hard ```

After SSL/HTTPS Change

```bash # Update site URLs wp option update siteurl 'https://yourdomain.com' wp option update home 'https://yourdomain.com'

# Regenerate .htaccess wp rewrite flush --hard ```

Quick Checklist

  1. 1.[ ] .htaccess exists and has WordPress rules
  2. 2.[ ] mod_rewrite is enabled (Apache)
  3. 3.[ ] AllowOverride is set to All (Apache)
  4. 4.[ ] try_files is configured (Nginx)
  5. 5.[ ] File permissions allow WordPress to write .htaccess
  6. 6.[ ] Rewrite rules are flushed in database
  7. 7.[ ] No conflicting .htaccess rules
  8. 8.[ ] Custom post types have rewrites registered

Permalink 404s are almost always configuration issues. Regenerate .htaccess, flush rewrite rules, and verify your server is set up for URL rewriting.

  • [WordPress troubleshooting: Fix Child Theme Not Enqueuing Parent Styles Correc](child-theme-not-enqueuing-parent-styles-correctly)
  • [Fix Database Connection Error Custom Socket Path Issue in WordPress](database-connection-error-custom-socket-path)
  • [Fix Debug Log Growing Deprecated Warnings Notices Issue in WordPress](debug-log-growing-deprecated-warnings-notices)
  • [Fix Fix Contact Form Not Sending On Wordpress Site Issue in WordPress](fix-contact-form-not-sending-on-wordpress-site)
  • [Fix Fix Open Basedir Restriction Blocking Wordpress Issue in WordPress](fix-open-basedir-restriction-blocking-wordpress)

<script type="application/ld+json"> { "@context": "https://schema.org", "@type": "TechArticle", "headline": "Fix WordPress Permalink 404 Error", "description": "Resolve WordPress 404 errors on pretty permalinks. Fix .htaccess rewrite rules, Apache AllowOverride, Nginx configuration, and mod_rewrite issues.", "url": "https://www.fixwikihub.com/fix-wordpress-permalink-404", "publisher": { "@type": "Organization", "name": "FixWikiHub", "url": "https://www.fixwikihub.com" }, "author": { "@type": "Person", "name": "FixWikiHub Editorial Team" }, "datePublished": "2025-11-17T09:49:50.078Z", "dateModified": "2025-11-17T09:49:50.078Z" } </script>