How to Share Logins and Users Between Multiple WordPress Sites

Updated on November 10, 2017

Our goal is to set up two WordPress websites which will share logins and the same users. Once a user has subscribed one website, she would be able to access the other website with the same role and capabilities.

To achieve this goal, we should be able to edit WordPress configuration file and update database tables. A general understanding of WordPress architecture and database structure is essential, as well as a basic knowledge of WordPress development. No worries if you’re not a pro. Just follow this post directives and ask your questions in the comments.

Before we start coding, we need to know where WordPress stores user roles and capabilities. So, our first step is to dive deep into database tables.

Important: The following will not work in the Kinsta environment. However, their support team might have an alternate solution for you. Feel free to open up a ticket with them.

User Data and Metadata

Out of the box, WordPress stores user related data into three tables: {$pref}options, {$pref}users and {$pref}usermeta.

  • The {$pref}options table stores the full list of available roles and capabilities in a row whose option_key field is {$pref}user_roles.
  • The {$pref}users table stores basic user data, like login, password, email, url, etc.
  • The {$pref}usermeta table stores user metadata.

When working on new WordPress installations, we don’t have to care about {$pref}user_roles row in {$pref}options table, because the corresponding option_value field has always the same value. We should consider this row just in case we’re working on existing installations where roles or capabilities have been changed.
No worries about {$pref}users table, as well, because it stores basic user data that we won’t change when sharing users between websites.
The {$pref}usermeta table is the only table we’re going to update to achieve our goal.

users and usermeta table structure (source: Codex Database Description)

users and usermeta table structure
(source: Codex Database Description)

{$pref}usermeta stores user metadata in key/value pairs. In this table five rows store the data that we have to consider.

Five rows in usermeta table store data concerning user capabilities, level and dashboard settings

Five rows in usermeta table store data concerning user capabilities, level and dashboard settings

The first row has the meta_key field set to {$pref}capabilities, and the corresponding meta_value field is a serialized array holding the user role. The second row stores the user level (note that user levels are deprecated from WordPress 3.0). The remaining three rows concern dashboard settings we won’t dive into in this post.
User role, level and settings are specific to the WordPress installation and are identified by the same $pref value. It is an important bit of information when our goal is to share users between websites, because we will have to duplicate these rows and change the meta_key field accordingly.

That’s all we have to know about user tables when we aim to share logins and users between new WordPress installations. When working on existing websites, we should consider that many plugins add extra rows to {$pref}usermeta, and we may be required to have a deeper look at database tables.

That being said about user tables, we can move a step forward. Now we have to define two specific constants into wp-config.php file.

Defining Custom User Tables – Share Logins

WordPress allows us to set custom tables instead of {$pref}users and {$pref}usermeta. This means that if two (or more) WordPress websites share one database, we can set the same users and usermeta tables for all of them. As a consequence, all websites which share these table will share the same users.

Note: In order to share the same users and usermeta tables, WordPress installations must share the same database.

We just need to define CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE into wp-config.php file, as shown in the following code:

// custom users and usermeta tables
define( 'CUSTOM_USER_TABLE', 'my_users_table' );
define( 'CUSTOM_USER_META_TABLE', 'my_usermeta_table' );
Note: On existing websites it’s mandatory to back-up WordPress installations before you make any changes to wp-config.php files and data tables

Now that we know what has to be done, it’s time to run our two WordPress installations.

Installing WordPress

For convenience, I will name the WordPress root folders first and second. first_ and second_ will be the respective table prefixes.
Now let’s run the first installation.

In this example we set the table prefix field to first_

In this example we set the table prefix field to first_

Note: All installations will share a single database, and we should provide each installation with a unique table prefix.

When the first WordPress website is up and running, we can edit its configuration file. Open /first/wp-config.php and add the following lines above the ‘stop editing’ comment:

$table_prefix  = 'first_';

define('WP_DEBUG', true);
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

// custom users and usermeta tables
define( 'CUSTOM_USER_TABLE', $table_prefix . 'users' );
define( 'CUSTOM_USER_META_TABLE', $table_prefix . 'usermeta' );

/* That's all, stop editing! Happy blogging. */

We have enabled debug mode forcing WordPress to store error notices and warnings into debug.log file (read more about this topic in An in-depth view on how to configure WordPress).
Then, we have defined CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE constants to first_users and first_usermeta tables. This way we’re not changing WordPress default settings.

We are done with the first installation. Next we have to copy wp-config.php from the first installation folder and paste it into the root folder of the second installation. Be careful to change the $table_prefix value accordingly:

$table_prefix  = 'second_';

define('WP_DEBUG', true);
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );

// custom users and usermeta tables
define( 'CUSTOM_USER_TABLE', 'first_users' );
define( 'CUSTOM_USER_META_TABLE', 'first_usermeta' );

CUSTOM_USER_TABLE and CUSTOM_USER_META_TABLE are set to the first installation’s values: first_users and first_usermeta. That’s all for the first installation.

share logins

WordPress is aware of existing users and we should set a non-existent email address for admin user

When running the second installation, we should set a non-existent email address for admin user as WordPress finds a number of existing users from first_users table.

WordPress creates an admin username for the second installation

WordPress creates an admin username for the second installation

Log into the second installation admin panel as admin and list WordPress users. You’ll find the new admin user and all users from the first website (this allows them to share logins). At this point, users from one site won’t be able to log into the other website.

The users in the second website won't inherit their roles from the first website

The users in the second website won’t inherit their roles from the first website

To grant users the same capabilities in both websites, we have to update {$pref}usermeta table.

Roles and Capabilities

If you are running new WordPress installations, you have not to care about {$pref}options table. You just need to update {$pref}usermeta table.

In our example, when a new user is created in the first website, WordPress adds first_capabilities and first_user_level rows in first_usermeta table. To give access to the second website, these rows should be duplicated, as shown in the image below:

second_usermeta_fields

When a new user is created in the second website, second_capabilities and second_user_level rows will be added to first_usermeta table.
In order to give the same roles and caps to users across websites, first_capabilities and first_user_level rows should be duplicated in second_capabilities and second_user_level. With these two pairs of rows in the same first_usermeta table, users would be able to access both websites with the same privileges.

To update all existing usermeta rows you may run a SQL query or update tables from phpMyAdmin. But what for users that will subscribe our websites from now on? According to WordPress Codex, we’d use a plugin or build a custom function.
And there we go!

Automatically Duplicate Caps and Levels with a Function

set_user_role is an action hook which triggers anytime a new user is created or an existing user’s role has been edited. Thanks to this action, we can automate usermeta table updates.
So, in the main file of a plugin add the following function:

function ksu_save_role( $user_id, $role ) {

	// Site 1
	// Change value if needed
	$prefix_1 = 'first_';
	
	// Site 2 prefix
	// Change value if needed
	$prefix_2 = 'second_';
	
	$caps = get_user_meta( $user_id, $prefix_1 . 'capabilities', true );
	$level = get_user_meta( $user_id, $prefix_1 . 'user_level', true );

	if ( $caps ){
		update_user_meta( $user_id, $prefix_2 . 'capabilities', $caps );
	}

	if ( $level ){
		update_user_meta( $user_id, $prefix_2 . 'user_level', $level );
	}
}

add_action( 'set_user_role', 'ksu_save_role', 10, 2 );

The callback function keeps three arguments, two of which are required: $user_id and $role.
What the function does is quite self-explanatory. get_user_meta returns the specified user meta field value. We have called this function twice to retrieve first_capabilities and first_user_level fields. Then we have used these values to add second_capabilities and second_user_level fields to first_usermeta table.

Upload ad activate this plugin into the first website.

To make installations work symmetrically, we just need to upload and activate the plugin in any installation, but setting the right values to prefixes. For instance, if we would activate this feature in the second website, we just have to declare the variables as follows:

$prefix_1 = 'second_';
$prefix_2 = 'first_';

So, edit and install the plugin into the second website and create a new user or change an existing user role. Then check the first website. The user roles will be exactly the same as the second website.

Conclusions

In this post I’ve explained how to grant the same privileges to users across independent WordPress installations. Once registered into a website, the user will be able to access all websites sharing the same users and usermeta tables.
I’ve supposed to work with new installations. If you’re working on existing websites, you should consider that some plugins could have updated usermeta table, or even created new tables storing user related data. In this case, a more accurate analysis of the database would be appropriate.

If you have any questions about how to share logins in WordPress, or you’d like to share your experience with us, feel free to join the conversation posting your comments.

The full code of our plugin is available in this public Gist

This article was written by Carlo Daniele
Carlo is a freelance front-end designer and developer. When he writes articles and tutorials, Carlo mainly deals with web standards, but when he plays with websites his best workmate is WordPress.

Hand-picked related articles

  1. Gravatar for this comment's author
    Steve Graham October 28, 2016 at 10:30 am

    Hi Carlo. Thanks for a very good explanation of what goes on. I am trying to get two sites using the same users and this has helped greatly to understand the process. I’ve followed your example and now need the abilty to sign in on one site and be automatically logged-in on the other. Have you taken this step?

    1. Gravatar for this comment's author
      Carlo Daniele November 10, 2016 at 12:26 pm

      Hi Steve. Actually, two independent installations could share user tables but they do not share the same login session. I’ve not delved into this aspect of the topic, but I suppose a multisite installation would be the best option to share login sessions.
      If your websites reside on the same domain, you could try to define the same cookie-path for both websites as suggested here: http://wordpress.stackexchange.com/a/131403/10012

    2. Gravatar for this comment's author
      Marius Ghitulescu March 14, 2017 at 6:57 pm

      Hey Steve, in case you didn’t test this already, I just did it and for the same domain it works by sharing cookie paths and domain keys and salts. I wrote a brief guide here if you need help: https://trickspanda.com/share-users-login-wordpress/

    3. Gravatar for this comment's author
      Maharshi Patel April 13, 2017 at 11:29 pm

      I had same problem and used plugin called User Session Synchronizer I had multisite network so had some issues I told him and he instantly replied to me in about a day and solved my problem and become friends
      ( setup is as simple as copy and paste website domain or subdomain in a box )

  2. Gravatar for this comment's author
    Daniel Schutzsmith February 23, 2017 at 5:40 am

    How can we do this but on different databases? Unfortunately on high-end sites like Pantheon sites so not share a database.

    Thanks,
    Dan

    1. Gravatar for this comment's author
      Carlo Daniele February 23, 2017 at 11:29 am

      Hi Daniel. I think there is no easy way to share users and usermeta tables between installs that do not share the same database. But you have other options to achieve your goal. The first and easiest is to create independent site sections based on custom post types or categories.

      Alternatively you may opt for a multisite + BuddyPress install where subsites share users thanks to BuddyPress. This is a more complicated solution and you should consider that the user management would be more complex than it is in a standard install.

      Here is a good post that could help you decide: https://halfelf.org/2011/dont-use-wordpress-multisite/

      1. Gravatar for this comment's author
        Daniel Schutzsmith February 23, 2017 at 6:01 pm

        Thanks for the tips! I’m weary of using multisite because the main website gets about 1 million uniques a month, which will surely overpower the smaller sites.

        I dreamt a solution last night that we’re gonna try. Essentially using the wpmu user sync plugin to sync basic user info across multiple sites while also using the rest API to handle editing custom fields made with ACF across servers. It’s a heck of a work around but I think this will work.

        1. Gravatar for this comment's author
          Carlo Daniele February 24, 2017 at 7:46 am

          It sounds good. I’m curious about the way you will handle custom fields via REST API. Keep us updated!

  3. Gravatar for this comment's author
    Lại Đình Cường March 29, 2017 at 9:19 am

    I can login but can’t access admin.

  4. Gravatar for this comment's author
    Maharshi Patel April 13, 2017 at 11:24 pm

    Hii Carlo, thanks for helping I have 5-6 multisite and I want to share user across all multisite networks is it possible? If yes can you please tell me what changes I need to work it properly ( I don’t have 5-6 subsite in multisite network I have 5-6 multisite network )

    1. Gravatar for this comment's author
      Carlo Daniele April 19, 2017 at 7:48 am

      Hi Maharshi. Actually, this plugin has been developed with independent installations in mind. It forces installations to share custom users and usermeta tables. That’s not required in WordPress multisite, as it uses the same tables (see Multisite table overview). Unfortunately, the administrator of a network has to manually enable each registered user to any site of the network and this could be unfriendly when you have to deal with many users and many sites.
      But luckily, a number of plugins allow to automatically share users among the sites of a network. Have a look at the following free plugins:
      https://wordpress.org/plugins/join-my-multisite/
      https://wordpress.org/plugins/multisite-user-management/
      https://premium.wpmudev.org/project/add-existing-users/
      https://premium.wpmudev.org/project/add-new-users/

      1. Gravatar for this comment's author
        Maharshi Patel April 19, 2017 at 10:15 pm

        Hey Carlo I don’t have five sites in one multisite network I have five-six multisite network with too many sites in it

        1. Gravatar for this comment's author
          Carlo Daniele April 20, 2017 at 1:33 am

          So, your question is “How to share users between multiple WP networks?”. Actually, it’s a complex topic for a comment, and it would require a much deeper view. But I’ve found this plugin that could be of help: https://github.com/stuttter/wp-multi-network

          1. Gravatar for this comment's author
            Maharshi Patel April 20, 2017 at 1:47 am

            I checked this but for my case it’s not working. I need something like you posted in this post I use multisite and it use one table as single WordPress site uses. if changing some code will make it working ? I already synced accounts across all network only issue I have is I can’t sync role if you can help me in that .. thank you for helping I followed this tutorial to sync account
            Tutorial: http://mikemclin.net/single-users-table-multiple-wordpress-sites/

  5. Gravatar for this comment's author
    Ariel Frailich May 11, 2017 at 5:51 am

    Thank you for a terrific and useful article!

    What should I do if I DON’T want users to have the same privileges across sites? Eg, an editor on site A should not automatically be an editor on site B. Can I simply skip syncing caps and levels, or will that create problems?

    Thank you for any advice!

    1. Gravatar for this comment's author
      Carlo Daniele May 15, 2017 at 2:51 am

      Hi. It’s a complex task. You can filter user capabilities through the user_has_cap filter, but I think this would require a lot of coding and testing. Instead, I would opt for a multisite install, which allows to easily admin user roles in subsite admin panels

  6. Gravatar for this comment's author
    Kuldip May 11, 2017 at 10:55 pm

    I followed above instruction and added role capabilities manually but it says on 2nd site:
    Sorry, you are not allowed to access this page.

  7. Gravatar for this comment's author
    Wilson Pina June 3, 2017 at 4:38 pm

    I’ve successfully followed the installation paths and managed to make the two installations communicte with the same database, however…

    How exactly can we automate the capabilities and levels with the function? Can we simply copy and edit the above code and add to to *ANY* plugin (say Akismet)?

  8. Gravatar for this comment's author
    Rui Pereira July 8, 2017 at 12:28 am

    Hi Carlo. Thanks for your sharing. It works perfect. I just have one problem.
    I install the plugin on the first site, then i go to the first site admin user and i click “update” and nothing is created in the database, so the user’s capabilities and user_level are not being created for the second website.
    If i create a new user it works, even when i update the user level on that user, that changes for both websites, not working just when i update an already existing user, what can be wrong or am i missing something? Thanks for everything!

Leave a Reply

Send this to a friend