Skip to main content
Blog|
How-to guides

How to import and export WordPress users

|
May 25, 2026|18 min read
HOW-TO GUIDESHow to import and exportWordPress usersHOSTNEYhostney.comMay 25, 2026

Short answer: WordPress’s built-in Tools > Export Personal Data covers single-user GDPR exports, but it does not bulk-export users to another site. For bulk moves, use the free Import Export WordPress Users plugin ( Users > Import / Export ), the WP All Import / WP All Export Pro pair when CSV mapping gets complex, or the wp user import-csv WP-CLI command if you have SSH access. Whatever path you pick, you cannot export working passwords – the WordPress password hash is tied to the source site’s salts, so every imported user has to reset their password on first login.

That covers the immediate “which tool do I use” question. The rest of this guide covers each path step by step, why passwords cannot be exported, how to handle role mapping and custom user meta, and which method matches which use case (site consolidation, membership migration, GDPR export, full-site move).

Methods at a glance#

MethodBest forHandles passwordsHandles rolesHandles user metaFree
Built-in Export Personal DataSingle-user GDPR / data subject requestNoNoPartial (plugin-aware)Yes
Import Export WordPress Users pluginBulk move under ~50,000 users between WordPress sitesLimited (see below)YesStandard meta onlyYes
WP All Import + WP All Export ProComplex custom meta, ACF fields, WooCommerce / MemberPressLimitedYes (with mapping rules)Full (custom mapping)No (paid)
wp user import-csv (WP-CLI)Developers with SSH, scriptable / automated importsLimitedYesBasic columns onlyYes
Manual CSV / SQLOne-off, ≤50 users, technical userLimitedYesManualYes
Full site migrationMoving an entire WordPress site (all users come along)Yes (same site, same salts)YesYesDepends on host

The “limited” passwords column is the central catch in this whole topic – covered in detail in the password handling section below.

What WordPress can and cannot move#

Every WordPress user has data in three places:

  • The wp_users table – login, email, registration date, hashed password, display name.
  • The wp_usermeta table – role, capabilities, nicename, description, profile preferences, plus anything plugins write (WooCommerce billing address, MemberPress membership IDs, ACF user fields, custom dashboards).
  • Auth and session state – active session tokens, application passwords, 2FA secrets, “remember me” cookies. These live in usermeta but are tied to the site’s secret keys.

What moves cleanly across sites: login, email, registration date, display name, role assignment, and most plugin-written usermeta if you map it.

What does not move cleanly:

  • Passwords. The hash is fine to copy literally, but it only validates on a site that has the same SECURE_AUTH_KEY and SECURE_AUTH_SALT in wp-config.php . Different salts, the same plaintext password produces a different hash. See the password handling section below.
  • Session tokens. Each session is signed by the source site’s keys. Moving them is pointless – they will not validate on the destination. (Imported users start with no active sessions; they create a fresh session the first time they log in. If you want to make logout / re-login one click for them after import, the WordPress logout URL guide covers adding a “Log out” item to a menu.)
  • Application passwords. Stored as hashes tied to the source site’s keys, same as user passwords. Imported users get a forced reset for these too.
  • 2FA secrets. Plugins like Wordfence Login Security and WP 2FA encrypt the TOTP secret with site-specific keys. Migrated users have to re-enroll in 2FA on the destination.

Plan for a forced password reset and a 2FA re-enrollment as part of any cross-site import. Telling users this up front is faster than fielding “I cannot log in” tickets later.

Path 1: The built-in Personal Data Export#

WordPress has had a Personal Data exporter since 4.9.6 (the GDPR release). It is designed for one user at a time, typically in response to a data subject request.

To run it:

  1. Tools > Export Personal Data in the admin.
  2. Enter the username or email of the user.
  3. Tick the request types you want included (WordPress core fields, comments, WooCommerce data if installed, any other plugin-registered exporters).
  4. Click Send Request. WordPress emails the user to confirm.
  5. Once they confirm, the export runs in the background and produces a downloadable ZIP of HTML and JSON files.

What you get: every piece of personal data WordPress and your installed plugins know about that user, in a portable archive. This is the correct tool for GDPR Article 15 / 20 requests.

What this tool does not do: bulk-export a list of users for moving them elsewhere. There is no “export all users to CSV” button in core WordPress. Every method below adds that capability.

Path 2: Import Export WordPress Users plugin (free)#

This is the most common bulk path. Install Import Export WordPress Users and WooCommerce Customers by WebToffee from the plugin repository. Free, actively maintained, handles up to tens of thousands of users on a normal host.

Exporting users#

On the source site:

  1. Users > Import / Export (added by the plugin).
  2. Pick Export at the top.
  3. Choose CSV as the file type.
  4. Pick which user roles to export, or leave it on “All” to grab everyone.
  5. (Optional) Filter by registration date range, last login range, or specific user IDs.
  6. Pick which columns to include – the defaults cover login, email, role, display name, registration date. Add columns for any usermeta keys you need (ACF fields, WooCommerce billing address, custom plugin meta).
  7. Click Export. The plugin streams a CSV file to your browser.

The exported CSV includes the hashed user_pass column by default. You can leave it in and rely on the destination doing a forced reset, or strip it before import (the destination side has an option for both).

Importing users#

On the destination site:

  1. Install the same plugin.
  2. Users > Import / Export > Import.
  3. Upload the CSV.
  4. Map the columns – in most cases the auto-mapping is correct, but check role , user_email , and any custom meta columns explicitly.
  5. Choose what to do with duplicates – skip, update, or update only if the destination user is newer.
  6. Choose whether to send a notification email with the password reset link. For cross-site imports, turn this on – it is the fastest way to get users back into the new site without you handling every one manually.
  7. Click Import. The plugin reports successes, failures, and skips at the end.

What to watch for#

  • Memory and timeout. A CSV with 10,000 users runs in seconds on a healthy site. A CSV with 100,000 users on a shared host with a 30-second PHP timeout will fail partway. Use WP-CLI (Path 4) for very large lists, or run the import from a fresh page reload to reset the timeout.
  • Role mapping. If the source has custom roles (e.g. subscription_active , added by a membership plugin), the destination must have that role registered before the import – otherwise WordPress silently demotes the user to Subscriber. Activate the membership plugin on the destination first, then import.
  • Plugin-specific user meta. WooCommerce customer data, MemberPress memberships, LearnDash course progress, and similar plugins each store user meta with their own keys. Map every meta column you care about. Anything not mapped is lost.

Path 3: WP All Import + WP All Export Pro (paid)#

WP All Export Pro and WP All Import (with the User Import Add-On) are the heavyweight option. They cost money, but they handle the complex cases the free plugins struggle with:

  • Custom user meta with non-trivial mapping – source uses _billing_address , destination uses shipping_default , with a transformation between them.
  • ACF user fields with structured data (repeaters, flexible content, post object references).
  • Conditional rules – import only users who registered after a date, only Subscribers, only users with a specific WooCommerce purchase, etc.
  • Cron-driven imports – keep two sites in sync by re-running the same import on a schedule.
  • XML / JSON sources in addition to CSV.

The workflow is the same shape as Path 2 – export from source, import to destination – but with a much richer mapping UI on both ends. If the free plugin’s auto-mapping does the job, save your money. If you spend two hours wrestling its column mapping and still cannot get a clean import, this is where to spend.

Path 4: WP-CLI (wp user import-csv)#

If you have SSH access to the destination site, WordPress’s command-line interface has a built-in user import command.

Exporting from the source#

WP-CLI does not have a single wp user export-csv command, but you can build one with wp user list :

wp user list --fields=user_login,user_email,user_pass,role,user_registered,display_name --format=csv > users-export.csv

This dumps every user in the standard fields to a CSV. Adjust --fields to add custom usermeta (combine with wp user meta get if you need fields that are not in wp_users ).

For a more complete export with usermeta, use a small loop:

wp user list --field=ID | while read uid; do
  email=$(wp user get $uid --field=user_email)
  role=$(wp user get $uid --field=roles)
  billing_city=$(wp user meta get $uid billing_city)
  # ... add other meta keys as needed
  echo "$uid,$email,$role,$billing_city" >> users-full-export.csv
done

This is slower than the plugin export but lets you script exactly what you want, including post-processing.

Importing on the destination#

Once you have the CSV:

wp user import-csv users-export.csv --send-email

The --send-email flag sends the standard “your account has been created” email to each imported user, which includes the password reset link. Drop the flag for silent imports.

CSV columns WP-CLI recognizes natively: user_login , user_email , user_pass , display_name , first_name , last_name , nickname , description , rich_editing , comment_shortcuts , admin_color , use_ssl , show_admin_bar_front , role . Anything else in the CSV is ignored – extra meta needs a separate wp user meta set pass after the import.

Large imports#

For very large user lists (50,000+), break the CSV into chunks:

split -l 5000 users-export.csv users-chunk-
for f in users-chunk-*; do
  wp user import-csv "$f"
done

This avoids long-running processes that can be killed by the host’s max execution time or memory limits.

Path 5: Manual CSV (small lists)#

For a one-off migration of ≤50 users where you do not want to install a plugin:

  1. Users > All Users on the source site.
  2. Tick Screen Options at the top and add any extra columns you want visible.
  3. Copy the visible data into a spreadsheet, plus any usermeta you can find from individual user profiles.
  4. Save as CSV.
  5. Import via the plugin in Path 2 or WP-CLI in Path 4.

This works, but the source-side data is incomplete (the All Users screen does not show every meta field), so this is only practical for handful-of-users scenarios. For anything bigger, use Path 2.

Why you cannot truly export WordPress passwords#

This is the part everyone trips on, so it deserves a dedicated section.

WordPress stores passwords as bcrypt-or-phpass hashes in wp_users.user_pass . Hashing is one-way – you cannot recover the plaintext. So far, identical to every other system.

The catch is that WordPress’s password verification function ( wp_check_password ) does not just compare hashes. It uses your site’s SECURE_AUTH_KEY and SECURE_AUTH_SALT from wp-config.php as part of the verification on newer installs. Different salts on the destination site means the same plaintext password produces a different hash – so even copying the literal hash column will not let users log in.

Three things you can do about this:

  1. Force a password reset on first login. The standard answer. Every plugin’s “Import users” feature has a toggle for this. After import, the user clicks the password reset link in the email they receive and sets a new password. Done.
  2. Copy the salts too. Edit the destination wp-config.php and copy the source’s SECURE_AUTH_KEY , SECURE_AUTH_SALT , and friends. Passwords now validate. This is a bad idea for cross-site migrations – you are pinning the destination’s session security to the source’s secrets, and if the source was ever compromised, the destination inherits the problem. The only legitimate use is full-site clones where the destination is the source (renamed domain, identical site).
  3. Skip the password column entirely. Import users without user_pass . WordPress generates a random password on insert. Email goes out with reset link. Functionally identical to option 1 with one less moving part.

Application passwords, 2FA secrets, and active session tokens have the same limitation for the same reason – they are signed or encrypted with the source’s secret keys. Migrated users have to re-enroll any of these on the destination.

Role mapping#

If your source site uses custom roles (added by a plugin like MemberPress, Restrict Content Pro, User Role Editor, or a custom code snippet), the destination must have those roles registered before the import runs – not just installed, but actively registered in the WordPress options table.

The order that works:

  1. Activate the same membership / role plugin on the destination.
  2. Let it register its roles (some plugins do this on activation, some need you to visit a settings page).
  3. Verify with WP-CLI: wp role list – all the expected custom roles should appear.
  4. Then import users.

If you skip step 3 and a role is missing, the user is silently demoted to Subscriber. The import reports success but every user ends up powerless on the destination. Not fun to debug.

For roles you want to map instead of preserve (e.g. source vip_member should become destination premium ), use Path 3 (WP All Import) – the free plugin in Path 2 has limited mapping support.

Preserving user meta#

Standard usermeta (capabilities, nicename, description, profile preferences) is handled by every plugin in this guide. The trouble is plugin-specific usermeta, where each plugin writes its own keys with its own conventions:

  • WooCommerce billing_first_name , billing_address_1 , shipping_* , _last_order , _customer_user . Often a couple dozen keys per customer.
  • MemberPress mepr-active , mepr-membership-<em> , mepr-txn-</em> .
  • LearnDash _sfwd-course_progress , _sfwd-quizzes , course completion meta.
  • bbPress – forum subscriptions, topic counts.
  • Easy Digital Downloads edd_user_* , license keys.
  • ACF user fields – whatever key you assigned to each field.

Before exporting, list every meta key being used by checking the source database:

SELECT meta_key, COUNT(*) FROM wp_usermeta GROUP BY meta_key ORDER BY COUNT(*) DESC;

Anything plugin-specific that has a high count is probably important. Add those columns to your export. The free plugin in Path 2 lets you pick custom meta columns directly; the WP-CLI path in Path 4 needs you to add wp user meta get calls.

Test on a single user first – import them on the destination, log in, and verify their stored data is intact. If WooCommerce billing addresses are missing or MemberPress shows them as expired, the meta did not come across and you need to revisit the export.

Common use cases#

Site consolidation - merging two sites into one#

Two WordPress sites, both have user bases, you want one combined site:

  1. Pick the destination (usually the bigger user base).
  2. Export users from the smaller site with the free plugin (Path 2) or WP-CLI (Path 4).
  3. Activate any custom-role plugins on the destination first.
  4. Import with skip duplicates turned on if the same email might exist on both sites.
  5. Force password reset for the imported users (they will not know their credentials work on the new site anyway).
  6. Decommission the smaller site.

This is the cleanest case – users come over once and the source goes away.

Membership site migration#

Moving a Woo Memberships / MemberPress / Restrict Content Pro site to a new host:

  1. The full-site migration path is almost always better than user-level export. See the Hostney section below – moving the whole site preserves passwords, sessions, and usermeta intact because the destination is the same site under a new home.
  2. If you must do users-only (rare), use Path 3 (WP All Import) and map every membership meta key explicitly. Anything missed means broken subscriptions on the destination.

GDPR data export request#

A user asks for their personal data under GDPR Article 15:

  1. Use Path 1 (built-in Personal Data Export) – it is the legally compliant tool.
  2. Do not export their data via a bulk tool and send them a CSV – the built-in exporter handles the full GDPR data set (comments, WooCommerce orders, plugin data via registered exporters) which a bulk users export does not.

Bulk creation from a CSV of new users#

A school, agency, or membership program is granting accounts to a known list:

  1. Build a CSV with user_login , user_email , display_name , role columns.
  2. Leave user_pass blank.
  3. Import via Path 2 or Path 4 with send notification email turned on.
  4. Every new user receives a “your account has been created” email with a password reset link. They set their own password on first visit.

This is faster and more secure than generating passwords yourself.

How Hostney handles user migration#

If you are moving users because you are moving the whole WordPress site to Hostney, the user-by-user export/import paths above are usually the wrong tool. A site-level migration preserves everything – users, hashed passwords (because the salts come too), session tokens, every piece of usermeta – in a single pass. Hostney has two pathways for that, both on the WordPress > Migrations page:

  • SSH migration. If you have SSH access to the source server, paste the credentials and Hostney pulls the entire site over directly – files plus database, including wp_users and wp_usermeta complete. The destination ends up as a byte-identical clone of the source, with wp-config.php salts copied so existing passwords keep working. Fastest path when SSH is available.
  • Plugin migration. If SSH is not an option, install the Hostney Migration plugin on the source WordPress, paste a single-use token from your control panel into it, and the source pushes the site to Hostney over an authenticated channel. Same end state as the SSH pathway – full site clone, users and passwords intact.

For both pathways, the WordPress Snapshots tab on the destination install is the pre-import safety net. If you want to dry-run a complex user import on a Hostney site, take a manual snapshot before running the import. If the role mapping turns out wrong or a custom plugin’s meta gets lost, restore the snapshot and try the import again with the right configuration. Snapshots are word-gated (type RESTORE ) so accidental clicks do not roll the site back unexpectedly.

What Hostney does not do at the platform level: bulk user export between two existing sites you own. That stays in the plugin layer (Paths 2-5 above), and the recommended workflow is to take a snapshot on the destination Hostney site first, run the import via a plugin, and roll back if it goes wrong.

Common mistakes#

  • Exporting the password column and expecting users to log in with their old password. Will not work unless you also copied the salts. Plan for a forced reset and tell users in advance.
  • Importing into a site without the custom-role plugin activated. Users silently get demoted to Subscriber. Activate role plugins first, verify with wp role list , then import.
  • Forgetting plugin-specific usermeta. WooCommerce customers without billing_* meta are functionally broken. Map every meta key that matters before exporting.
  • Importing into the wrong site. Easy to do when the source and destination are open in adjacent tabs. Use distinct admin colour schemes (Users > Your Profile > Admin Color Scheme) on each site to avoid this.
  • Sending the password reset email before users know to expect it. Users see “reset your password” out of the blue and assume it is a phishing attempt. Tell them in advance – “we are moving your account to a new site, you will get a password reset email today, click the link from it within 24 hours.”
  • Running a 100,000-user CSV import through the web UI on shared hosting. PHP timeout kills it halfway. Use WP-CLI (Path 4) or split the CSV into chunks.
  • Not testing on one user first. A bad import on 10,000 users is much harder to clean up than a bad import on one. Always run with a single test row, verify the destination state, then run the full import.

Frequently asked questions#

Can I export WordPress users with their passwords intact?#

Not in a way that lets them log in on a different site. The password hash is fine to export but it only validates against the source site’s SECURE_AUTH_KEY / SECURE_AUTH_SALT . The standard answer is force password reset on first login.

What is the largest user list I can import at once?#

The free plugin in Path 2 handles tens of thousands on a healthy host but starts to struggle past 50,000 due to PHP memory and timeout limits. WP-CLI in Path 4 has no practical ceiling – users have imported millions of rows in chunks. Use WP-CLI for anything over ~20,000 to be safe.

Will the import overwrite my existing users?#

It depends on the duplicate-handling setting. The free plugin in Path 2 offers Skip, Update, and Update-if-newer modes. WP-CLI’s default is to update by email match. Pick Skip if you want a strict additive import; pick Update if you want the source to take precedence.

Can I import users from a non-WordPress system?#

Yes, with mapping. Build a CSV with the columns WordPress recognizes ( user_login , user_email , role , etc.) and import via any of Paths 2-4. The source system does not have to be WordPress.

Are user IDs preserved across the import?#

Usually not. The destination assigns new auto-increment IDs. If something else in your import references users by ID (post authorship, foreign keys in custom tables), you need a mapping step from old IDs to new IDs after the import.

Does WP-CLI's wp user import-csv send emails?#

Only if you pass --send-email . Without the flag, users are created silently with no notification.

What about WordPress Multisite?#

Multisite has an extra layer – users belong to the network, not to individual sites. Adding a user to a site means associating an existing network user with that site. Path 2’s plugin has Multisite-aware modes; WP-CLI uses wp user add-role and wp user remove-role to manage per-site membership. The export/import flow stays similar but the role-mapping step also covers per-blog roles.

Summary#

The right user export/import path depends on what you are actually doing:

  1. Single user GDPR request – Tools > Export Personal Data (built-in).
  2. Bulk move under 50,000 users between WordPress sites – Import Export WordPress Users plugin (free, Path 2).
  3. Complex custom meta or membership plugin migration – WP All Import + WP All Export Pro (paid, Path 3).
  4. Developer with SSH, scriptable or very large imports – WP-CLI’s wp user import-csv (Path 4).
  5. Moving the entire WordPress site – full-site migration, not user-level export. Hostney’s SSH or plugin migration handles this end-to-end including passwords and usermeta.

Whatever path you pick, plan for a forced password reset and a 2FA re-enrollment for every imported user. Test on a single user before running the full import. Map every plugin-specific usermeta key you care about. And if you are not sure which path fits, start with Path 2 – the free plugin handles the majority of real-world cases and you can always upgrade to a different method if it falls short.

If you are also planning the broader move, why most WordPress migrations fail and how to migrate WordPress to another hosting provider cover the surrounding pieces – DNS, file transfer, search-and-replace – that turn a user import into a complete site move.