301 vs 302 Redirects in WordPress: Which One to Use

A 301 redirect says a URL has moved for good. A 302 redirect says it has moved for now and the old address is coming back. For nearly every WordPress job (a changed slug, a merged post, a new domain, the switch to HTTPS) you want a 301. Use a 302 only when you genuinely plan to bring the original URL back.
The catch is that WordPress’s own redirect functions default to 302, so a redirect written in code without a status code is temporary whether you meant it or not. Below: the two side by side, the cousins (307, 308, 404 and 410), how Google reads them, what WordPress does on its own, the usual mistakes and how to check what a URL is really sending. If you just want the steps to set one up, our guide to redirecting a URL in WordPress covers that. This post is about choosing the right one.
What the numbers actually mean
A redirect is an HTTP response with a 3xx status code and a Location header holding the new address. The code tells everyone why.
- 301 Moved Permanently. The resource lives at the new URL now. Update your records. Browsers are allowed to cache this, and they do, sometimes for a long time.
- 302 Found. The resource is somewhere else at the moment. Keep using the old URL. Browsers do not cache it unless the server adds caching headers.
That caching matters. A wrong 301 can stick in visitors’ browsers after you fix it on the server, because the browser never asks again. A 302 is easy to take back.
301 vs 302 at a glance
| 301 | 302 | |
|---|---|---|
| Meaning | Moved permanently | Moved temporarily |
| Browser caching | Cached, often for a long time | Not cached by default |
| How Google reads it | Strong signal the new URL should be the canonical one | Weak signal; the old URL tends to stay the canonical one |
| URL that tends to show in search | The new one, once Google has processed it | The old one |
| Typical WordPress use | Changed slug, merged post, domain or HTTPS move, permalink structure change | Maintenance page, login and form redirects, a test, a page that is coming back |
| Permanent sibling / temporary sibling | 308 (keeps the request method) | 307 (keeps the request method) |
Default in wp_redirect() |
No, you have to pass 301 | Yes |
307 and 308, briefly
Older browsers had a habit of turning a POST into a GET when they followed a 301 or 302, which quietly dropped form data. 307 Temporary Redirect and 308 Permanent Redirect were added to fix that: they mean the same as 302 and 301, but the browser must repeat the request with the same method and body. Google treats 308 like 301 and 307 like 302. A content site rarely needs either.
404 vs 410 for content that is gone
If a post is deleted and nothing replaces it, the honest answer is an error, not a redirect to something unrelated.
- 404 Not Found means nothing is here. It does not say whether that is permanent.
- 410 Gone means it was here, you removed it on purpose, and it is not coming back.
Both end up with the URL dropped from search. A 410 states the intent more clearly, and Google has said it can be processed a little faster, but the practical difference is small. Use 410 when you deliberately prune content, 404 for everything else, and a 301 only when there is a page that really answers the same need.
How search engines treat them
Google describes redirects mostly in terms of canonicalisation: when two URLs lead to the same content, which one should it show? A permanent redirect (301 or 308) is a strong signal that the target should be the canonical URL. A temporary one (302 or 307) is a weak signal, so Google usually keeps the source URL as the one it shows, because you told it the move is temporary.
Two points that get lost in the “301 vs 302 SEO” arguments:
- It is about which URL wins, not about losing value. Google has said for years that redirects of either kind do not throw away ranking signals. The cost of a wrong 302 is that the old URL can keep showing in results while the page lives somewhere else.
- A long-lived 302 may end up treated as permanent. Google has said that if a temporary redirect stays in place for a long time, it may start treating it as a permanent one. There is no published timetable and you have no control over when it happens, so do not plan around it. If the move is permanent, say so.
In Search Console, an old URL that redirects shows up as “Page with redirect” in the Pages report. That is not an error. It is Google confirming it saw your redirect, and our guide to the Crawled, currently not indexed status has a quick table of the other statuses you will see next to it. If the new URL is the one that will not get indexed, the redirect is rarely the cause; check the usual suspects in why Google isn’t indexing your WordPress site, starting with a wrong canonical tag pointing back at the old URL.
What WordPress does on its own
We checked this in the WordPress core source (version 7.0) rather than trusting memory.
wp_redirect() and wp_safe_redirect() default to 302
Both functions in wp-includes/pluggable.php have $status = 302 as the default. wp_safe_redirect() also checks that the destination is on an allowed host and, if it is not, sends the visitor to the admin URL instead. So any plugin, theme or snippet that calls either one without passing 301 is sending a temporary redirect. For a login or “thanks for submitting” redirect, that is correct. For an old URL that moved, it is a bug.
Both also send an X-Redirect-By header, set to WordPress unless the caller passes its own name. Many plugins do pass one, which makes that header the quickest way to find out who sent a redirect.
Canonical redirects are 301
redirect_canonical() in wp-includes/canonical.php runs on every front-end request. When the requested URL is not the canonical version (an ugly ?p=123 URL when you use pretty permalinks, a missing trailing slash, the wrong host) it sends a 301 to the proper one. Before it does, it checks whether its own target would redirect again, to avoid creating a chain.
Old slug redirects are 301, for posts only
When you change the slug of a published post, WordPress stores the old slug in a _wp_old_slug custom field. Later, when a request returns a 404, wp_old_slug_redirect() looks for a post with that old slug (and also checks for a changed date in date-based permalinks) and sends a 301 to its current URL.
The fine print, straight from the code:
- It skips hierarchical post types, which includes pages. Rename a page and WordPress will not redirect the old URL for you.
- It only records the change if the post was already published.
- It only kicks in when the old URL would otherwise be a 404. If something new takes over that address, the redirect stops.
A safety net for posts, nothing for pages. That is why our permalink change workflow still adds an explicit 301 every time.
When to use each
Use a 301 (or 308) when
- You changed a post or page slug.
- You merged several posts into one, or replaced an old post with a better one.
- You moved to a new domain, to HTTPS, or settled on www or non-www.
- You changed the site-wide permalink structure.
- You removed a page and something else genuinely covers the same need.
Use a 302 (or 307) when
- A page is down for maintenance and will be back.
- You are running a short test that sends some visitors elsewhere.
- A product is out of stock for a while and you point its page somewhere useful until it returns.
- The redirect is part of a flow, not a URL change: after login, after a form submission, after checkout.
If you are not sure which list you are on, ask one question: is the old URL coming back? If the answer is “probably not”, it is a 301.
Where to set a redirect
- A redirect plugin. The easiest route and the right one for most sites. Look at the default status code in its settings, and turn on the option to create a 301 automatically when a published URL changes, if it has one. That also covers pages, which core skips.
- Server config.
.htaccesson Apache or the nginx server block. Faster, but a typo can take the site down. - Cloudflare rules. Redirect Rules and Bulk Redirects run at the edge, before the request reaches your server. You pick the status code in each rule, so check it.
Pick one home for your redirects. Rules spread across a plugin, .htaccess and Cloudflare are how chains and loops start.
Common mistakes
A 302 for a permanent move
Usually an accident: a snippet calling wp_redirect() without a status, or a plugin left on its default. Visitors never notice; search keeps showing the old URL.
Redirect chains
A chain is A to B to C. They build up quietly. You renamed a post in 2023, renamed it again this year, and your HTTP to HTTPS rule sits in front of both, so an old link now takes three or four hops. Every hop is a round trip, and Googlebot follows only a limited number. The fix: point every old URL straight at the final one.
Redirect loops
A loop is A to B to A, and the browser gives up with a “too many redirects” error. On WordPress the classic cause is Cloudflare’s Flexible SSL mode: Cloudflare talks to your server over plain HTTP, WordPress (or a rule) redirects to HTTPS, Cloudflare sends the request over HTTP again, and round it goes. Two rules in different layers that disagree about www or the trailing slash do the same thing.
Sending everything to the homepage
Google tends to treat redirects to an unrelated page as soft 404s. Redirect to the closest real match, or return a 404 or 410.
Thinking a redirect changes what a link means
Affiliate plugins often route links through a /go/ or /recommends/ URL that redirects to the merchant. That redirect does not mark the link as paid. It still needs rel="sponsored" (or nofollow), which we cover in adding nofollow links in WordPress.
How to check what a URL really sends
Do not trust the plugin screen. Ask the URL itself.
- One hop:
curl -I https://example.com/old-url/prints the response headers. Look at the status line (HTTP/2 301orHTTP/2 302), thelocation:header and, if present,x-redirect-by:to see who sent it. - The whole chain:
curl -sIL https://example.com/old-url/follows every hop and prints each set of headers. Any 3xx after the first one is a chain. - Just the count:
curl -sL -o /dev/null -w "%{num_redirects} %{url_effective}\n" https://example.com/old-url/prints how many redirects it took and where it ended up. Anything above 1 is worth fixing.
In the browser, open dev tools, go to the Network tab, tick Preserve log and load the old URL. The first row shows the 3xx status; click it to see the Location header. Two things trip people up here. First, a cached 301 may show as coming “from disk cache”, so test in a private window. Second, Chrome often shows a 307 Internal Redirect from http:// to https://. That one is the browser enforcing HSTS on its own; your server never saw the request. If curl shows a 301 for the same URL, the server is fine.
The last step: point your own links at the final URL
A redirect is for links you cannot edit: other people’s sites, old emails, bookmarks. Links inside your own posts you can edit, and leaving them on the old URL means every reader and crawler takes an extra hop through your site forever. It is also how chains begin: the next rename turns that one hop into two.
So after any URL change, search your content for the old address and swap in the new one. An internal link check or crawler will list internal links that hit a redirect, and the same pass that finds broken links catches the ones that now 404. It is worth doing for another reason too: some audit tools count links by exact URL, so a page whose links all go through a redirect can look like it has none, which is how perfectly good posts end up on a list of orphaned pages.
Full disclosure: we make JnK Linkweave, and its Pro version has a URL changer that finds an old URL in your post content, previews every post it would touch, replaces it and lets you roll the batch back. It does not create redirects, so you still set the 301 with one of the methods above.
Frequently asked questions
Is a 302 redirect bad for SEO?
Not in itself. A 302 is correct when a move really is temporary. The problem is using one for a permanent move: Google treats a 302 as a weak signal, so it tends to keep showing the old URL instead of the new one. Google has said a long-lived 302 may eventually be treated as permanent, but there is no timetable, so if the old URL is not coming back, use a 301.
Does WordPress automatically redirect when I change a slug?
For published posts, yes. WordPress saves the old slug and sends a 301 to the new URL when the old one would otherwise return a 404. It does not do this for pages or other hierarchical post types, and it stops working if a new post takes the old address. Add an explicit 301 with a redirect plugin or server rule so the behaviour does not depend on those conditions.
Should I use a 301 or a 410 for a deleted post?
Use a 301 only if another page genuinely covers the same topic, such as a newer post you merged it into. If nothing replaces it, return a 410 Gone (or a plain 404). Redirecting deleted posts to the homepage or an unrelated page tends to be treated as a soft 404 and annoys visitors who expected something specific.