WordPress "You Do Not Have Upload Permission" Error: How to Fix It
TL;DR: The error comes from your WordPress server, not from the iPhone app, browser, or script making the request. The two most common causes are: (1) the user behind your Application Password lacks the upload_files capability, or (2) a security plugin / WAF is blocking /wp-json/wp/v2/media before WordPress evaluates the request. Promote the user to Author (or any role that includes upload_files), or exempt the media endpoint from the offending firewall rule, and uploads work immediately. For a wider view of all upload failures (not just permission errors), see our companion guide Cannot Upload Images to WordPress: 8 Causes and Fixes.
Verified against WordPress 6.7 on June 2, 2026.
Quick Diagnosis: What the Response Tells You
Before changing anything, look at the HTTP response your client receives. Each combination of status code and error body points to a different root cause.
| HTTP status | Error code | Likely cause | First step |
|---|---|---|---|
| 403 | rest_cannot_create | User role lacks upload_files | Change role to Author or higher (see Root Cause 1) |
| 401 | rest_invalid_authentication | Application Password wrong or revoked | Regenerate Application Password (see Root Cause 4) |
| 403 | HTML page, no JSON | Security plugin or WAF blocked the request | Check Wordfence / iThemes / Cloudflare event log |
| 503 / timeout | (no body) | WAF or rate limiter dropped the connection | Inspect Cloudflare or origin firewall logs |
| 200 | HTML page, not JSON | WP REST API disabled by plugin | Disable "Disable REST API" or equivalent plugin |
How the Error Actually Reaches Your Client
When a client uploads a photo to WordPress, it makes a POST request to /wp-json/wp/v2/media. The request carries an Authorization header with your username and an Application Password — a token you generate in Users -> Profile -> Application Passwords, a WordPress core feature since version 5.6 (official integration guide).
WordPress core then runs a permission check before accepting the file. (If you would rather skip Application Passwords entirely, the SnapPress Connect plugin uses a QR-pair flow that side-steps role-related upload issues for our users.) The relevant logic in WP_REST_Attachments_Controller::create_item_permissions_check() is:
if ( ! current_user_can( 'upload_files' ) ) {
return new WP_Error(
'rest_cannot_create',
__( 'Sorry, you are not allowed to upload media on this site.' ),
array( 'status' => rest_authorization_required_code() )
);
} If the user behind the Application Password does not have the upload_files capability, WordPress returns HTTP 403 with a JSON body containing "code": "rest_cannot_create". Your client receives that response and surfaces it as "You do not have upload permission."
This means the message is literal: WordPress is telling you the user is not allowed to upload. The next step is figuring out why. The full list of role capabilities is documented on the official WordPress Roles and Capabilities page.
Root Cause 1: The User Role Lacks upload_files
This is the most frequent cause we observe in SnapPress support cases. WordPress has five default roles, and only some of them can upload media:
| Role | Can upload media? |
|---|---|
| Administrator | Yes |
| Editor | Yes |
| Author | Yes |
| Contributor | No |
| Subscriber | No |
If your Application Password belongs to a Contributor or Subscriber, every upload attempt will fail with the permission error, even though authentication succeeds (the password itself is valid; it just does not buy enough access).
How to check the role
- Log in to your WordPress admin at
https://your-site.example/wp-admin/. - Open Users -> All Users.
- Find the user whose Application Password you put into the client app.
- Look at the Role column.
If the role is Contributor, Subscriber, or anything custom that does not include upload_files, that is your problem.
How to fix it (least-privilege first)
The safest fix is to promote the user to Author. Author is the minimum default role that includes upload_files, plus the ability to create and publish the user's own posts. It cannot manage other users, plugins, or settings, so it is the recommended choice when only the upload workflow is required.
Promote to Editor if the user also needs to edit and publish posts from other authors, or Administrator only when the user genuinely needs full site control (for example, a single-owner site you manage yourself). After changing the role, generate a fresh Application Password under the now-correct user and update the client app. The fresh password is recommended but not strictly required; it eliminates the "stale credential" hypothesis.
What if the role is custom?
If your site uses a role plugin like Members or User Role Editor, the named role may not match the defaults. Open the role editor, find the role assigned to your user, and confirm the upload_files checkbox is enabled. Save and retry. Custom roles are also where most permission regressions hide; if uploads once worked and silently stopped working after a plugin update, this is the place to start. For multi-user sites, the cleanest approach is a dedicated custom role with upload_files plus the minimum posting capabilities you actually need.
Root Cause 2: A Security Plugin Is Blocking the REST API
If your user role already includes upload_files and uploads still fail, the next suspect is a security plugin intercepting the REST API request before WordPress core sees it. Common offenders:
- Wordfence — firewall rules can match unusual Authorization headers; Rate Limiting can throttle REST traffic.
- iThemes Security / Solid Security — REST API hardening options can block
/wp-json/wp/v2/*from anything other than a logged-in browser session. - Disable REST API — the plugin literally named that blocks all REST endpoints by default; you must whitelist
/wp/v2/mediafor app uploads to work. - SecuPress, Shield Security, and similar plugins have equivalent settings.
When one of these blocks the request, the client sees the same "no upload permission" symptom because the plugin returns a 403 that resembles WordPress's own error. The difference is that core's current_user_can() check never runs.
Wordfence specifics
Two settings are worth checking. Open Wordfence -> All Options -> Firewall Options:
- Brute Force Protection: aggressive lockout settings can ban an Application Password after a single retry.
- Rate Limiting: thresholds for "If anyone's requests exceed..." apply to REST traffic too. A mobile app retrying failed uploads can trip these.
If you suspect Wordfence, open Wordfence -> Tools -> Live Traffic and trigger an upload from the client. If the request is blocked, the reason appears in the log entry with the rule that fired. The full firewall reference is at wordfence.com/help/firewall/.
iThemes Security / Solid Security specifics
Solid Security has moved its REST API hardening between releases. In recent versions, look under Security -> Settings -> Advanced -> WordPress Tweaks for the REST API option (older builds placed it under Tools). The two states you care about are:
- Default (REST API enabled) — what app uploads need.
- Restricted — limits REST endpoints to logged-in browser sessions; Application Password requests can fail here.
Switch to Default if you can, or whitelist /wp/v2/media explicitly. The exact label may differ by version; refer to the Solid Security documentation for your release.
How to diagnose
Deactivate suspect plugins one at a time and retry the upload between each. The plugin whose deactivation makes uploads succeed is the culprit. Once identified, find the specific setting blocking the REST API and exempt /wp-json/wp/v2/media from it. Every plugin in the list above supports per-endpoint exemption in some form, though the menu paths vary by version.
Root Cause 3: A WAF Is Blocking the Request
If your site sits behind a web application firewall (Cloudflare WAF, Sucuri, AWS WAF, BunkerWeb), the WAF can reject the upload request before it ever reaches your WordPress server. Cloudflare in particular has WAF managed rules that target large multipart POST bodies and unusual Content-Type combinations, both of which a media upload uses. See Cloudflare's WAF documentation for the rule catalog.
Symptoms vary, but typically you get one of:
- HTTP 403 with a Cloudflare error page in the response body.
- HTTP 503 or a timeout, with no error body at all.
- HTTP 200 with an HTML response instead of JSON.
Cloudflare-specific narrow fix
Do not blanket-disable Cloudflare's managed rules. Instead, identify the specific rule that fired:
- Open the Cloudflare dashboard and go to Security -> Events (formerly Firewall Events).
- Trigger a failing upload from your client.
- Filter events by host or by the URI
/wp-json/wp/v2/media. The blocking rule appears with its ruleset ID and rule ID. - Create a custom rule under Security -> WAF -> Custom Rules that skips only that specific managed rule for the upload endpoint:
(http.request.uri.path eq "/wp-json/wp/v2/media") and (http.request.method eq "POST") Set the rule action to "Skip" targeted at the specific ruleset / rule you identified, not all managed challenges. Place the rule above any "Block" rules in priority. This keeps protection on for the rest of /wp-json/ while allowing legitimate media uploads through.
Root Cause 4: Authentication Failure or Revoked Application Password
Application Passwords do not have a built-in expiration; once issued, they remain valid until manually revoked. So the symptom here is usually HTTP 401 with rest_invalid_authentication, not the 403 permission error. But it is worth checking when nothing else fits:
- Open WordPress admin -> Users -> Profile -> Application Passwords.
- Confirm the password you registered in the client app is still listed.
- If it was removed (manually, by a security plugin, or by a password change event), generate a new one and update the client.
- Confirm your site is reachable over HTTPS. WordPress strips the Authorization header on plain HTTP for security; an http-to-https mismatch can produce intermittent 401s.
- Confirm no security plugin or custom code has disabled Application Passwords via the
wp_is_application_passwords_availablefilter.
Some security plugins automatically revoke Application Passwords on certain events (password changes, role changes, suspicious activity). If your role was recently changed, that alone may have revoked existing passwords. Regenerating is a one-minute fix.
Confirming the Fix from the Command Line
Once you have applied a fix, you can verify uploads work without involving the client app at all. From any machine with curl, run:
curl -u 'your-username:your-application-password' \
-X POST \
-H 'Content-Disposition: attachment; filename=test.jpg' \
-H 'Content-Type: image/jpeg' \
--data-binary @test.jpg \
https://your-site.example/wp-json/wp/v2/media A successful upload returns HTTP 201 and a JSON body that includes the new media item's id, source_url, and media_details. Anything else points back to the diagnostic table at the top of this article, and the response body usually tells you which row applies.
If you cannot run curl, the same test can be done from Postman or any HTTP client that supports Basic authentication and multipart form data. The endpoint, credentials, and expected response are identical.
Why a Mobile App Cannot Fix This For You
It is tempting to assume an upload bug must be in the app, because the app is the visible part of the chain. But the WordPress REST API is the authoritative gatekeeper for what any client (browser, iOS app, Zapier, command line) is allowed to do. The app's job is to send a well-formed request with valid credentials and surface the response. If WordPress says "no upload permission," changing the app cannot make the answer change. The fix has to happen on the WordPress side: role, plugin settings, WAF rules, or Application Password.
This is by design and is a strength of the REST API model. The same checks protect your site whether someone uses a phone app, a desktop client, or writes a custom script. For alternatives that avoid the REST API entirely, see how to upload to WordPress without Jetpack; for HEIC-specific upload pitfalls (a related but distinct failure mode), see our HEIC and WordPress guide.
Summary Checklist
- Read the HTTP status code and error code from the actual response. Match against the diagnostic table at the top.
- Check the WordPress user role. It must include
upload_files(Author or higher among the defaults). - If the role is correct, deactivate security plugins one at a time and retry uploads.
- If no plugin is the cause, check your WAF event log; add a narrow rule exception for
/wp-json/wp/v2/mediaonly for the specific firing rule. - Confirm the Application Password is still listed in the user's profile and your site is on HTTPS; regenerate if needed.
- Verify end-to-end with curl before returning to the client app.
Following this order resolves the majority of "no upload permission" reports we see from SnapPress users. The error message is doing its job; it just needs the right context to act on.
Frequently Asked Questions
- Why does WordPress return 'You do not have upload permission' to my iPhone app?
- The REST API endpoint
/wp-json/wp/v2/mediarequires the WordPress user to hold theupload_filescapability. Subscriber and Contributor roles do not have it. If your iPhone app authenticates as a user in one of those roles, every upload attempt returns HTTP 403 withrest_cannot_createas the error code. Promoting the user to Author (or any role that includesupload_files) resolves it. - I am the site administrator and I still get 'no upload permission'. What is happening?
- When the user role is correct, the next likely cause is a security plugin or WAF rule that blocks the REST API. Wordfence, iThemes Security, Solid Security, and "Disable REST API" plugins all have settings that can reject non-browser REST traffic. Cloudflare WAF rules targeting
/wp-json/have the same effect. Use your firewall's event log to find the specific blocking rule, then exempt only that rule for/wp-json/wp/v2/media. - Does the WordPress Application Password give the same role as the user it belongs to?
- Yes. Application Passwords are issued per user, and any request authenticated with one runs as that user with that user's exact capabilities. If the underlying user is a Subscriber, the Application Password cannot upload, even if it was generated successfully. Application Passwords do not have a built-in expiration; they remain valid until manually revoked.
- How do I confirm the upload_files capability from a terminal?
- Run curl with
-u username:application-passwordand POST to/wp-json/wp/v2/mediawith a small test image. HTTP 201 with a JSON body containing the new media ID means uploads work. HTTP 403 with coderest_cannot_createmeans the role lacksupload_files. HTTP 401 withrest_invalid_authenticationmeans the Application Password is wrong or revoked. HTTP 403 from a non-WordPress response body (HTML error page, Cloudflare challenge) means an upstream filter is blocking the request before WordPress sees it. - Should I just promote the user to Administrator?
- Only as a last resort, and only for sites you fully control. The principle of least privilege says you should give the user the smallest role that grants
upload_files, which is Author. Reserve Administrator for accounts that actually need to manage settings, plugins, or other users. A dedicated custom role with onlyupload_filesplus posting capabilities is even safer for shared sites.