{"id":2009531,"date":"2022-04-04T19:21:23","date_gmt":"2022-04-04T19:21:23","guid":{"rendered":"https:\/\/wpx.net\/blog\/?p=2009531"},"modified":"2025-02-21T11:57:07","modified_gmt":"2025-02-21T11:57:07","slug":"restore-admin-access-wordpress","status":"publish","type":"post","link":"https:\/\/wpx.net\/blog\/restore-admin-access-wordpress\/","title":{"rendered":"Breaking and Entering: Restore Admin Access to WordPress"},"content":{"rendered":"\n<p class=\"has-text-align-left\">If you spend enough time in the business of creating and maintaining WordPress websites, there will inevitably come a time when a customer will reach out to you with a specific request: help them restore admin access to their WordPress website.<\/p>\n\n\n\n<p><span style=\"white-space: normal;\">They will explain how they used to have somebody who worked on their website, but that person is now gone for whatever reason, and the customer can\u2019t access their own website to make some important and urgent changes. Could you possibly help them out?<\/span><\/p>\n\n\n\n<p><span style=\"white-space: normal;\">WordPress makes it very easy to recover an account when the user has lost their password, but how to proceed if the user doesn\u2019t have admin access to their WordPress website?<\/span><\/p>\n\n\n\n<p><span style=\"white-space: normal;\">Let\u2019s find out what options we have.<\/span><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Disclaimer\"><\/span>Disclaimer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Obviously, the very first thing you should do is make sure the request is legit. How to do that is beyond the scope of this article but my point is that you should not blindly accept to do such work and that you should always make sure you\u2019re working with the website owner and not with a nefarious third party. Be smart!<\/p>\n\n\n\n<p>Now that we have set this aside, let\u2019s discuss how we can approach this mess.<\/p>\n\n\n\n<p>In order to help a customer in a situation as the one described above, you will probably end up needing access to their hosting control panel, or FTP access to their website. But even if such access is readily available, it is worth spending 5 minutes to try a couple of low-effort things first.<\/p>\n\n\n\n<p>After all, why try to squeeze through the chimney or the basement window if the front door is left unlocked?<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Restore_Admin_Access_Non-Invasive_Attempts\"><\/span>Restore Admin Access: Non-Invasive Attempts<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>The thing I would do first in a situation like that is try to figure out if the customer does have admin access, but they have forgotten about it.<\/p>\n\n\n\n<p>During installation, WordPress creates an admin account and \u2014 unless changed by hand \u2014 assigns it the username \u2018admin\u2019. I will attempt password recovery by going to the following URL:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;example.com\/wp-login.php?action=lostpassword<\/code><\/pre>\n\n\n\n<p><strong>Note<\/strong>: in this and subsequent code examples, I will be using the example.com domain; you should of course change that to your actual domain name.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"360\" height=\"415\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/lost-password-recovery-attempt.png\" alt=\"Try to restore WordPress admin access with admin username\" class=\"wp-image-2009532\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/lost-password-recovery-attempt.png 360w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/lost-password-recovery-attempt-260x300.png 260w\" sizes=\"auto, (max-width: 360px) 100vw, 360px\" \/><figcaption class=\"wp-element-caption\">Trying admin before anything else<\/figcaption><\/figure>\n\n\n\n<p>If this account exists, WordPress will send an email with recovery instructions to the email address associated with it. If your customer is lucky, this email address belongs to them. Ask them to check their inbox. If they get a message with a recovery link in it, your job is done, but you will still bill them for the whole hour. Right?<\/p>\n\n\n\n<p>However, it is very likely this attempt will fail with an \u201cError: There is no account with that username or email address\u201d message. It is a good security practice to assign a different username to the initial admin account, and these days all but the most incompetent sysadmins will have renamed it.<\/p>\n\n\n\n<p>So let\u2019s try something else instead.<\/p>\n\n\n\n<p>A default WordPress installation comes with a pre-published blog post called \u2018Hello World!\u2019. The authorship to this post is assigned to the admin user. Many WordPress themes that ship with some sample data do the same.<\/p>\n\n\n\n<p>You could try opening the \u2018Hello World!\u2019 blog post which has the post ID of 1 by typing:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;example.com\/?p=1<\/code><\/pre>\n\n\n\n<p>This URL links to the author page associated with the WordPress User ID of 1:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code> https:&#47;&#47;example.com\/?author=1<\/code><\/pre>\n\n\n\n<p>If the person responsible for the initial setup of this website has been careless or lazy, we have a chance to learn the username of the admin user from the authorship metadata.<\/p>\n\n\n\n<p>The specific behavior of the blog post page and the author page is different depending on the theme and the customization settings. If you are lucky, it will show the author, and the author&#8217;s name might contain a link to their WordPress author page, like this:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;example.com\/author\/someuser<\/code><\/pre>\n\n\n\n<p>You can try that username (someuser) to attempt password recovery and tell your customer to once again check their mailbox. If they get a recovery link, you will have been successful.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Success_Rate\"><\/span>Success Rate<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>The stuff I described above will work only if whoever set up WordPress is an amateur or has been extremely careless. It is a universal security practice to never call the admin user \u2018admin\u2019, and most good WordPress developers will have put measures in place to block resource enumeration (that thing with ?author=1 we used).<\/p>\n\n\n\n<p>Realistically speaking, the chances of recovering admin access using the tips above are very low. But since it only requires a trivial amount of time and effort to try, I feel obliged to try this first before attempting more effective but invasive measures.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Restoring_Admin_Access_via_FTP_or_the_Hosting_Control_Panel\"><\/span>Restoring Admin Access via FTP or the Hosting Control Panel<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>For brevity, I will assume that the customer has already provided you with access to the web host control panel, or at the very least with FTP\/shell access. There are several ways to restore admin access to the WordPress dashboard:<\/p>\n\n\n\n<p>1. Create a new admin account<br>2. Reset the password of an existing admin account<br>3. Change the email address of an existing admin account (i.e. take over an account)<br>4. Promote an existing lower-level account to admin status<\/p>\n\n\n\n<p>I prefer creating a new account, but there are different real life possibilities that might make another option preferable. This is why I will show you how to perform all operations, and I will leave it up to you and your customer to decide which one to perform.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Possible_Solutions\"><\/span>Possible Solutions<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>There are two ways to achieve our task, and they both involve modifying the WordPress database.<\/p>\n\n\n\n<p>One method is to write several database queries and execute them via php file. It is quick and effective, but not really fun to write about. Also, it is highly specific to the task at hand \u2014 any knowledge you will obtain through using it will be limited to solving the same exact problem and nothing else.<\/p>\n\n\n\n<p>My preferred method involves using a small GUI tool called Adminer (https:\/\/www.adminer.org). While I will use it to show you how to fix that particular issue (restore user access to the WordPress admin panel), I hope you will recognize the overall usefulness of that tool and add it to your bag of tricks.<\/p>\n\n\n\n<p>Despite the horrible name (and a UI to match\u2026), Adminer is a very competent tool to work with MySQL\/MariaDB databases. Compared with phpMyAdmin, it has a simpler interface and requires no installation: all features are contained within a single PHP file that you can deploy and delete as needed.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Where_to_Get_Adminer\"><\/span>Where to Get Adminer<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Go to adminer.org and scroll down to the Downloads section. For this tutorial, I will grab the&nbsp;<strong>\u2018<\/strong><a href=\"https:\/\/www.adminer.org\/latest-mysql-en.php\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>Adminer for MySQL, English only<\/strong><\/a>\u2018 version. The \u2018full\u2019 version supports other database engines and other interface languages which are of no use for the purpose of this tutorial.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"783\" height=\"251\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-mysql-english-only.png\" alt=\"\" class=\"wp-image-2009533\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-mysql-english-only.png 783w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-mysql-english-only-300x96.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-mysql-english-only-768x246.png 768w\" sizes=\"auto, (max-width: 783px) 100vw, 783px\" \/><\/figure>\n\n\n\n<p>Go ahead and grab that file, then save it to the root folder of the WordPress site you need to access. I prefer to rename the file to adm.php while I am at it, because it saves time typing the URL in the browser, and does not require remembering.<\/p>\n\n\n\n<p><strong>Note:<\/strong>&nbsp;By itself, Adminer is harmless. It can\u2019t do anything if you don\u2019t have the database name, db user name, and db user password. However, it does expose the database to the world, and somebody&nbsp;<em>could<\/em>&nbsp;find a way to exploit that. That is why I take some additional precautions to restrict access to Adminer.<\/p>\n\n\n\n<p>1. I place Adminer into a random, 8-character directory under root<br>2. I limit access to that directory by creating a .htaccess file in &nbsp;it with the following contents:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Order Deny,Allow\nDeny from all\nAllow from 123.123.123.123<\/code><\/pre>\n\n\n\n<p>where 123.123.123.123 is of course my actual IP address.<\/p>\n\n\n\n<p>3. I set a reminder to myself to delete the Adminer folder 24 hours after I am done using it.<\/p>\n\n\n\n<p>After doing all of this, I try accessing Adminer from the browser:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>https:&#47;&#47;example.com\/{random-string}\/adm.php<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Navigating_Adminer\"><\/span>Navigating Adminer<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Upon successful loading, Adminer greets me with the following underwhelming login screen:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"617\" height=\"297\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login.png\" alt=\"\" class=\"wp-image-2009534\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login.png 617w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login-300x144.png 300w\" sizes=\"auto, (max-width: 617px) 100vw, 617px\" \/><\/figure>\n\n\n\n<p>To get past this screen, you need to provide the database name, db user and db password. You can get them from within the\u00a0<a href=\"https:\/\/wpx.net\/blog\/wpconfig-immense-power\/\" data-type=\"link\" data-id=\"https:\/\/wpx.net\/blog\/wpconfig-immense-power\/\"><code>wp-config.php<\/code>\u00a0<\/a>file that is located under the website root folder:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ ** MySQL settings - You can get this info from your web host ** \/\/\n\/** The name of the database for WordPress *\/\ndefine( 'DB_NAME', 'Database' );\n\/** MySQL database username *\/\ndefine( 'DB_USER', 'Username' );\n\/** MySQL database password *\/\ndefine( 'DB_PASSWORD', 'Password' );\n\/** MySQL hostname *\/\ndefine( 'DB_HOST', 'localhost' );<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"About_WordPress_Table_Names\"><\/span>About WordPress Table Names<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>While viewing&nbsp;<code>wp-config.php<\/code>&nbsp;to get the DB credentials, I also suggest that you scroll down and take note of the&nbsp;<code>$table_prefix<\/code>&nbsp;setting.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/**\n* WordPress Database Table prefix.\n*\n* You can have multiple installations in one database if you give each\n* a unique prefix. Only numbers, letters, and underscores please!\n*\/\n$table_prefix = 'wp_';<\/code><\/pre>\n\n\n\n<p>While a large number of WordPress sites use the default prefix \u2018wp_\u2019 to name their tables, there are many exceptions to this rule where the prefix is different or there is no prefix at all.<\/p>\n\n\n\n<p>There are also cases where within the same database there are multiple tables with the same name but different prefixes (a plugin called WP Reset that makes database snapshots is notorious for that).<\/p>\n\n\n\n<p>Throughout this tutorial, I assume that the tables use the standard prefix of wp_, but I recommend that you check out and take note just in case.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"And_now_back_to_our_regularly_scheduled_programming\"><\/span>And now, back to our regularly scheduled programming<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Going back to Adminer, I suggest that you tick the \u2018Permanent login\u2019 checkbox. It will store a cookie in your browser and add an automated login link to the left:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"610\" height=\"325\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login-saved.png\" alt=\"\" class=\"wp-image-2009535\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login-saved.png 610w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-login-saved-300x160.png 300w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/figure>\n\n\n\n<p>This will allow you to close and\/or restart your browser and resume work at leisure, without having to go back to&nbsp;<code>wp-config.php<\/code>&nbsp;to fetch the database settings.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Dont_Panic\"><\/span>Don\u2019t Panic<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>\u201cI like the cover,\u201d he said. \u201cDon\u2019t Panic. It\u2019s the first helpful or intelligible thing anybody\u2019s said to me all day.\u201d<br>\u2015 Douglas Adams, The Hitchhiker\u2019s Guide to the Galaxy<\/p>\n\n\n\n<p>When you see the main screen of Adminer for the first time, you might feel the urge to close the browser window and start running until you hit the ocean; then start swimming.<\/p>\n\n\n\n<p>However, I am here to help you suppress that primal panic and do the thing you came to do. Adminer looks scary only the first time, and for a short amount of time; after you have seen how easy it is to use, you will warm up to it \u2014 I promise!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"First_Things_First_Backup_the_Database\"><\/span>First Things First: Backup the Database<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>This one is non-negotiable. No matter how good you are with databases, and how much experience with WordPress you have, you should only proceed if you have a fresh backup.<\/p>\n\n\n\n<p>However, you have a choice here: either export the&nbsp;<em>whole<\/em>&nbsp;WordPress database, or only the tables on which we will be working (wp_users and wp_usermeta). This one I leave up to you to decide.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"A_Full_Export\"><\/span>A. Full Export<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>If you want to export the whole table, you need to click on Export in the top left corner and select output type, format, etc. Do not forget to tick the checkboxes next to Tables and Data below the export button!<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"798\" height=\"424\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-export-all.png\" alt=\"\" class=\"wp-image-2009536\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-export-all.png 798w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-export-all-300x159.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/adminer-export-all-768x408.png 768w\" sizes=\"auto, (max-width: 798px) 100vw, 798px\" \/><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"B_Single_Table_Export\"><\/span>B. Single Table Export<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>This one makes more sense to me. As you will be working on a single table at a time (wp_users followed by wp_usermeta), you only need to make sure you don\u2019t break any of these two tables.<\/p>\n\n\n\n<p>Scroll down the list to the left until you find the wp_users table and click on the select link to the left. You should see something like that (without the emojis that I have used to hide sensitive data, of course):<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"352\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export-1024x352.png\" alt=\"\" class=\"wp-image-2009537\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export-1024x352.png 1024w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export-300x103.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export-768x264.png 768w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export-1200x412.png 1200w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-table-export.png 1273w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>Before you proceed, let\u2019s do the backup first. Click on the checkbox next to the Modify column to select all rows, then select \u2018save\u2019 and \u2018sql\u2019 in the Export tab and click on the Export button to create an SQL file and save that in a safe location.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Solution_1_Create_New_User\"><\/span>Solution 1: Create New User<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>To add a new entry to that table, click on the \u2018New item\u2019 link at the top right.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"677\" height=\"469\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-add-user.png\" alt=\"Restore WordPress admin access by creating a new user with admin privileges\" class=\"wp-image-2009538\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-add-user.png 677w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-add-user-300x208.png 300w\" sizes=\"auto, (max-width: 677px) 100vw, 677px\" \/><\/figure>\n\n\n\n<p>Leave ID blank. It will auto-increment to the next lowest available number. Fill&nbsp;<strong>user_login<\/strong>&nbsp;(this is the username),&nbsp;<strong>user_nicename<\/strong>,&nbsp;<strong>user_email<\/strong>&nbsp;and&nbsp;<strong>display_name<\/strong>. Leave the rest blank for the time being.<\/p>\n\n\n\n<p>You next need to create a password for the new user, and store the hash of that password in&nbsp;<strong>user_pass<\/strong>. For this, I use the very convenient&nbsp;<a href=\"https:\/\/codebeautify.org\/wordpress-password-hash-generator\" target=\"_blank\" rel=\"noreferrer noopener\">WordPress Password Hash Generator<\/a>&nbsp;made available by&nbsp;<a href=\"https:\/\/codebeautify.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">CodeBeautify.org<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"268\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator-1024x268.png\" alt=\"\" class=\"wp-image-2009539\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator-1024x268.png 1024w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator-300x79.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator-768x201.png 768w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator-1200x314.png 1200w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/codebeautify-wordpress-password-hash-generator.png 1482w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>When you click on the \u2018Random\u2019 button, the tool will issue a brand new random password for your new user, and will generate the hash record for it. Copy the hash (the long string that begins with $P$B) and paste it into&nbsp;<strong>user_pass<\/strong>&nbsp;within Adminer, then press \u2018Save\u2019 to create the new user record.<\/p>\n\n\n\n<p><strong>Important:&nbsp;<\/strong>Note the ID number assigned to that user \u2014 you will need it in a minute. Store the password as well.<\/p>\n\n\n\n<p>We are almost there!<\/p>\n\n\n\n<p>Your new user is created, but it has no role within WordPress just yet. To fix that, you must add two more records for that user:&nbsp;<strong>User Level<\/strong>&nbsp;and&nbsp;<strong>Capabilities<\/strong>. These details are kept in the table called wp_usermeta. You already know the drill:&nbsp;<\/p>\n\n\n\n<p>1. Locate wp_usermeta in the list on the left<br>2. Click on \u2018select\u2019 to the left of the table name<br>3. Make a backup of that table<br>4. Add records (this time there will be two operations)<\/p>\n\n\n\n<p>To assign&nbsp;<strong>User Level<\/strong>, you will create a new record (click on \u2018New item\u2019):<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"608\" height=\"422\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-userlevel.png\" alt=\"\" class=\"wp-image-2009540\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-userlevel.png 608w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-userlevel-300x208.png 300w\" sizes=\"auto, (max-width: 608px) 100vw, 608px\" \/><\/figure>\n\n\n\n<p>Leave umeta_id blank. For&nbsp;<strong>user_id<\/strong>, supply the ID number of the new user. For&nbsp;<strong>meta_key<\/strong>, supply the value&nbsp;<code>wp_user_level<\/code>. Set&nbsp;<strong>meta_value<\/strong>&nbsp;to 10. Press \u2018Save and insert next\u2019 to store the record and return to the same insert screen. Adminer will confirm insertion (\u2018Item xxx has been inserted\u2019).<\/p>\n\n\n\n<p>To assign&nbsp;<strong>Capabilities<\/strong>, you will create another record.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"602\" height=\"426\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-capabilities.png\" alt=\"\" class=\"wp-image-2009541\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-capabilities.png 602w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-usermeta-capabilities-300x212.png 300w\" sizes=\"auto, (max-width: 602px) 100vw, 602px\" \/><\/figure>\n\n\n\n<p>For&nbsp;<strong>user_id<\/strong>, supply the ID number of the new user. For&nbsp;<strong>meta_key<\/strong>, supply the value&nbsp;<code>wp_capabilities<\/code>. Set&nbsp;<strong>meta_value<\/strong>&nbsp;to&nbsp;<code>a:1:{s:13:\"administrator\";b:1;}<\/code>&nbsp;and press \u2018Save\u2019 to store the record and gtfo.<\/p>\n\n\n\n<p>And\u2026 you\u2019re done! You can now try to log in with your newly created admin account via&nbsp;<a href=\"https:\/\/example.com\/wp-login.php\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/example.com\/wp-login.php<\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Solution_2_Reset_the_Password_of_an_Existing_User\"><\/span>Solution 2: Reset the Password of an Existing User<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>This operation requires a single operation within Adminer. Instead of adding a new record to the database, you will edit an existing record. However you first need to find out the user record to modify, and this might not be easy, if the website has many users. Here\u2019s how to go about it:<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"21_Find_Users_with_Admin_Privileges\"><\/span>2.1 Find Users with Admin Privileges<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>1. Locate the&nbsp;<strong>wp_usermeta<\/strong>&nbsp;table in the list on the left and click on \u2018select\u2019 next to it<br>2. Click on the = sign next to the&nbsp;<strong>meta_key<\/strong>&nbsp;column header to open the table search function and search for&nbsp;<code>wp_user_level<\/code>&nbsp;with a&nbsp;<strong>meta_value<\/strong>&nbsp;of 10:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"903\" height=\"495\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp_usermeta-existing-users-capabilities.png\" alt=\"\" class=\"wp-image-2009542\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp_usermeta-existing-users-capabilities.png 903w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp_usermeta-existing-users-capabilities-300x164.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp_usermeta-existing-users-capabilities-768x421.png 768w\" sizes=\"auto, (max-width: 903px) 100vw, 903px\" \/><\/figure>\n\n\n\n<p>This will give you a (hopefully, very short!) list of user IDs that associate with WordPress users that have admin capabilities. Keep this list open in a browser tab for the time being \u2014 you will have to go back to it shortly.<br>3. Locate the&nbsp;<strong>wp_users<\/strong>&nbsp;table in the list on the left and click on \u2018select\u2019 next to it<br>4. Create a backup (in case you skipped Solution 1, go back and see how to do it)<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"22_Filter_Admin_Users_by_ID\"><\/span>2.2 Filter Admin Users by ID<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>If your website has many registered users (an active blog, a membership website or a Woocommerce store\u2026), the wp_users table might be hundreds or thousands of rows long. You will need to filter the table so that only those records who have admin capabilities remain visible. To do that, click on Search once again, and prepare the following query:<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter\"><img loading=\"lazy\" decoding=\"async\" width=\"939\" height=\"225\" src=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-filter-IDs.png\" alt=\"\" class=\"wp-image-2009543\" srcset=\"https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-filter-IDs.png 939w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-filter-IDs-300x72.png 300w, https:\/\/wpx.net\/blog\/wp-content\/uploads\/2022\/03\/wp-users-filter-IDs-768x184.png 768w\" sizes=\"auto, (max-width: 939px) 100vw, 939px\" \/><\/figure>\n\n\n\n<p>In the first field, you will select ID, and in the second you will change the equal operator (=) to IN, which looks into a list of values. In the last field, you will type the IDs of the WP admins you obtained in Step 2 (comma separated).<\/p>\n\n\n\n<p>You should then ask your customer which profile to reset. To help them remember, send them the contents of user_nicename, user_email and\/or display_name for these entries. Hopefully, they will recognize an account that belongs to them, and for which they can receive emails. If the miracle happens, go to&nbsp;<a href=\"https:\/\/example.com\/wp-login.php?action=lostpassword\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/example.com\/wp-login.php?action=lostpassword<\/a>&nbsp;and plug that username or email address into the recovery field; then let the customer pick their own password.<\/p>\n\n\n\n<p>Alternatively, you could reset their password yourself (see the part about user_pass in Solution 1 above) and send them the new password over email or IM, but password sharing is a horrible practice. Don\u2019t let any customer drag you down into this.<\/p>\n\n\n\n<p><strong>Side note:<\/strong>&nbsp;As you can see, I really dislike seeing other people\u2019s login credentials. If your customer is so clueless to the extent they don\u2019t know their own WP username, or can\u2019t reset their own password once you help them find their username, you aren\u2019t really helping them by resetting the password of that account. It is better to create a new admin account and stick with it, and to begin billing this customer for support and maintenance. But because customers are different (and sometimes difficult\u2026). I am giving you options. Use them wisely!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Solution_3_Change_the_email_address_of_an_Existing_User\"><\/span>Solution 3: Change the email address of an Existing User<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>You can suggest this to your customer as a means of recovering access to the admin account used by the previous maintainer. By changing the email address associated with it, the customer will be able to reset the password.<\/p>\n\n\n\n<p>The way to approach this is similar to the one outlined in Solution 2: filter WP accounts with admin rights, send the list to your customer and wait for instructions about which account to edit.<\/p>\n\n\n\n<p>Once they come back to you, you simply need to edit the existing record for&nbsp;<strong>user_email<\/strong>. I would also change the value of&nbsp;<strong>user_login<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Solution_4_Promote_an_Existing_User_Account_to_Admin_Status\"><\/span>Solution 4: Promote an Existing User Account to Admin Status<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>While possible and easy to implement, this is another solution that I generally dislike. Account permission levels exist for a reason. If your customer has been operating with restricted permissions before, perhaps there is no reason to change this now.<\/p>\n\n\n\n<p>Also, sharing username\/password access is still prevalent among less technically inclined users, and by agreeing to promote an existing user, you may unwittingly let somebody else in to cause trouble.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Recap\"><\/span>Recap<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>So\u2026 here is what we did in this post.<\/p>\n\n\n\n<p>Hopefully, you helped a customer regain admin access to their WordPress website. I first showed you a couple of simple tricks to trigger a password reset for an existing profile under the control of that customer. Depending on how the website was designed and configured, these might not have worked, but the time and effort involved were so low that it didn\u2019t really matter.<\/p>\n\n\n\n<p>I then showed you how to deploy a small GUI tool called Adminer and use it to access the database from a web browser. With the help of Adminer, you made a database backup, and then proceeded to execute one of several possible recovery scenarios (create new admin account; take over existing admin account; promote another account to admin status). I also explained why I prefer the first method to every other alternative.<\/p>\n\n\n\n<p>By showing you how to do all of the above, I actually took you on a crash course into quick, small-scale database querying and editing, and I also lifted the curtain a bit on some WordPress internals like user permission levels. We will have the chance to talk more about these details in future blog posts.<\/p>\n\n\n\n<p>I sincerely hope these hints will tickle your fancy and that you will end up spending some time exploring the WordPress database with Adminer to advance your knowledge about the platform.<\/p>\n\n\n\n<p>And, circling back to the very beginning of this article (breaking and entering, remember?) I want to ask: Have you ever had to play the locksmith and break into a WordPress website? How did you do it?<\/p>\n\n\n\n<p>Leave a comment below \u2014 I promise your secrets will be safe with me and all readers of the WPX blog!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If you spend enough time in the business of creating and maintaining WordPress websites, there will inevitably come a time when a customer will reach out to you with a specific request: help them restore admin access to their WordPress website. They will explain how they used to have somebody who worked on their website, [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":2015365,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"cybocfi_hide_featured_image":"","footnotes":""},"categories":[89],"tags":[],"ppma_author":[111],"class_list":["post-2009531","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-security"],"blocksy_meta":[],"authors":[{"term_id":111,"user_id":3,"is_guest":0,"slug":"ivan-arnaudov","display_name":"Ivan Arnaudov","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/168c2caf170cc2d43ef2ec57bc8af7347f86a5f5e825ee86026e52878df349b2?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/posts\/2009531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/comments?post=2009531"}],"version-history":[{"count":15,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/posts\/2009531\/revisions"}],"predecessor-version":[{"id":2022051,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/posts\/2009531\/revisions\/2022051"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/media\/2015365"}],"wp:attachment":[{"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/media?parent=2009531"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/categories?post=2009531"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/tags?post=2009531"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/wpx.net\/blog\/wp-json\/wp\/v2\/ppma_author?post=2009531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}