Sql 1396 error

Learn how to fix MySQL ERROR code 1396 related to creating and removing users account

The MySQL ERROR 1396 occurs when MySQL failed in executing any statement related to user management, like CREATE USER or DROP USER statements.

This error frequently appears when you run statements to create or remove users from your MySQL database server.

MySQL has a bug that triggers this error when you remove a user without using the DROP USER statement.

This bug prevents you from re-creating a user previously deleted using the DELETE statement.

For example, suppose you create and then delete the developer account as shown below:

CREATE USER `developer` IDENTIFIED BY "developer";
DELETE FROM mysql.user WHERE user = 'developer';

Then the next time you create the user developer in your database server, you will trigger the error as follows:

mysql> DELETE FROM mysql.user WHERE user = 'developer';
Query OK, 1 row affected (0.00 sec)

mysql> CREATE USER `developer` IDENTIFIED BY "developer";
ERROR 1396 (HY000): Operation CREATE USER failed for 'developer'@'%'

To fix this, you need to run a DROP USER statement for the same user account.

MySQL will respond with the same error, but after that you can create the user again.

Take a look at the following example:

mysql> CREATE USER `developer` IDENTIFIED BY "developer";
ERROR 1396 (HY000): Operation CREATE USER failed for 'developer'@'%'

mysql> DROP USER `developer`;
ERROR 1396 (HY000): Operation DROP USER failed for 'developer'@'%'

mysql> CREATE USER `developer` IDENTIFIED BY "developer";
Query OK, 0 rows affected (0.01 sec)

Even though the DROP USER statement above throws an error, the same user can be created using the CREATE USER statement after that.

The error hasn’t been fixed up to MySQL version 8.0.26 as of today.

Other ways the error can be triggered

The error can also occur when you run the CREATE USER statement for an already existing user:

mysql> CREATE USER `developer` IDENTIFIED BY "developer";
Query OK, 0 rows affected (0.01 sec)

mysql> CREATE USER `developer` IDENTIFIED BY "developer";
ERROR 1396 (HY000): Operation CREATE USER failed for 'developer'@'%'

The same error could happen when you run the DROP USER or ALTER USER statement for a non-existing user account:

mysql> DROP USER `notuser`;
ERROR 1396 (HY000): Operation DROP USER failed for 'notuser'@'%'

mysql> ALTER USER dev@localhost IDENTIFIED BY 'newPassword';
ERROR 1396 (HY000): Operation ALTER USER failed for 'dev'@'localhost'

To list all existing users in your database server, you need to query the user table in your mysql database.

SELECT the user and host column from the table as follows:

SELECT user, host FROM mysql.user;

Please note that you may have different values between % and localhost in the host column.

Here’s an example from my database:

+------------------+-----------+
| user             | host      |
+------------------+-----------+
| developer        | %         |
| mysql.infoschema | localhost |
| mysql.session    | localhost |
| mysql.sys        | localhost |
| nathan           | localhost |
| root             | localhost |
+------------------+-----------+

The % value in the host column is a wild card that allows the user account to connect from any host location.

The localhost value means that you need to connect from the localhost only.

MySQL treats two identical user account with different hosts value as different users.

When you don’t specify the host value in the CREATE USER statement, it will default to the % wild card.

-- Create developer@% account
CREATE USER `developer` IDENTIFIED BY "developer";

-- Create developer@localhost account
CREATE USER `developer`@localhost IDENTIFIED BY "developer";

The statements above will create two developer accounts with different hosts:

+------------------+-----------+
| user             | host      |
+------------------+-----------+
| developer        | %         |
| developer        | localhost |
+------------------+-----------+

When you trigger the ERROR 1396 that’s not caused by the bug above, be sure to check out the users you have in your database first.

Do you have trouble adding MySQL database users?

Often MySQL error code 1396 pops up when we try to create a user that already exists.

At Bobcares, we often receive requests to solve such Database errors as part of our Server Management Services.

Today we will discuss MySQL error code 1396 in detail and see how our Support Engineers fix this error for our customers.

What is the MySQL error code 1396?

All databases should have valid users that have privileges to do database queries as well as edits.

Unfortunately, errors are common while querying in the MySQL databases. MySQL error code 1396 is often related to website restore, migration, etc. In such scenarios, this error occurs when we try to create an already existing user in MySQL.

Similarly, we often see this error even if we delete the already existing user too.

A typical error message when adding MySQL user appears as:

How we fix MySQL error 1396?

We now know the scenario that causes MySQL error 1396. Let’s see how our Support Engineers fix this error.

Recently, one of our customers got MySQL error 1396 while trying to create a new user. He checked and found that the user already existed in the database. So, he deleted the user and tried creating the user once again.

But unfortunately, he received the same error.

Here, our Support Engineers started troubleshooting by checking all occurrences of the database user in MySQL table.

We used the command:

use mysql;
select * from user;

There was a user with the same name and this was creating problems while new user creation. Here, the customer was trying to delete the user using the command DROP user username. In MySQL, if you specify only the user name part of the account name, it uses a hostname part of ‘%’. This stopped removing the correct user.

Therefore, we had to remove the exact MySQL user using:

mysql>delete from user where user='username'and host='localhost';

Further, we used the FLUSH PRIVILEGEs command to remove all the caches. FLUSH PRIVILEGE operation will make the server reload the grant tables.

So, we executed the following query and created the newuser ‘user’ successfully.

mysql>flush privileges;
mysql>CREATE USER 'user'@'localhost' IDENTIFIED BY 'xxx123';

This resolved the error effectively.

[Need help to solve MySQL error code 1396?- We’ll help you.]

Conclusion

In short, the MySQL error 1396 occurs when we try to create a user that already exists in the database. Today’s write-up also discussed the various causes of this error and saw how our Support Engineers fixed it for our customers.

PREVENT YOUR SERVER FROM CRASHING!

Never again lose customers to poor server speed! Let us help you.

Our server experts will monitor & maintain your server 24/7 so that it remains lightning fast and secure.

GET STARTED

var google_conversion_label = «owonCMyG5nEQ0aD71QM»;

Troubleshooting ERROR 1396A few weeks back, we faced an issue in a replication environment for a Managed Services client:

LAST_ERROR_MESSAGE: Worker 2 failed executing transaction ‘UUID:GTID’ at master binlog.0012345, end_log_pos 98765; Error ‘Operation CREATE USER failed for ‘test_user’@’10.10.10.10” on query. Default database: ‘mysql’. Query: ‘CREATE USER ‘test_user’@’10.10.10.10’ IDENTIFIED WITH ‘mysql_native_password’ AS ‘************”

After some initial investigation, we noticed that the user in the replica didn’t exist! Was MySQL going crazy? But then the customer mentioned they had the following error in the primary before being able to execute the query successfully:

root@localhost [mysql]> CREATE USER ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘************’ WITH MAX_USER_CONNECTIONS 10;

ERROR 1396 (HY000): Operation CREATE USER failed for ‘test_user’@10.10.10.10

But we knew that the first command couldn’t be replicated (since failed commands are never logged to the binlog), so the question was, what happened, and why was MySQL having trouble creating a nonexistent user?

If you do quick research, you will find a few posts offering some options: 

  • Execute FLUSH PRIVILEGES.
  • DROP USER and then FLUSH PRIVILEGES.
  • Many mentions that this is a reported bug.

And fair enough, if you try the options mentioned above, you’ll fix the issue eventually. Still, I wanted to take a deeper look at why this happened and what should be the correct approach to fix it (and understand WHY something will fix it); so I decided to do some tests and create a post for whoever faces an issue like this in the future, in the hope that you’ll too understand it.

Let’s start with a reminder: You shouldn’t manipulate the mysql grant tables manually, and if you do it, you should be sure that you know what you’re doing. So to start, here’s a summary of how MySQL’s privileges work.

A summary of MySQL privileges

At startup, MySQL reads the grant tables and loads them into memory, so whenever it needs to check if a user is allowed to read this or to connect there, MySQL can look for the privileges faster (reading from memory).

MySQL keeps track of the privileges using the grant tables, so when we issue a CREATE USER, internally, it translates to

  • Insert into mysql.user
  • Insert into mysql.db

If we GRANT or REVOKE, it will translate into a

  • Insert into mysql.table_priv
  • Update in mysql.db
  • Delete in mysql.table_priv.

And so on. Please note this isn’t an exact step-by-step on what happens; it’s just an example of a few internal things MySQL needs to execute.

Finally, after each Account Management Statement, MySQL reads the new privileges into memory, and the changes are applied.

With this, MySQL makes it easy for us to manipulate privileges; should you need to delete a user, instead of manually deleting every row in each grant table, you can execute a DROP USER, and that’s it.

Even though it’s simpler that way, sometimes users decide to go the “hard way” and manipulate the privileges manually: instead of DROP USER, execute a DELETE from grant tables. But, as mentioned before, MySQL won’t know about these changes because the grant tables were read already, and the privileges are in memory.

Let’s go through the issue mentioned above

First step: The user was created in the primary server:

root@localhost [(none)]> CREATE USER ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected (0.00 sec)

Second step: After some tests, they wanted to drop the user and create it again, but they went with manually deleting the user:

root@localhost [(none)]> use mysql

Database changed

root@localhost [mysql]> delete from user where user=‘test_user’;

Query OK, 1 row affected (0.00 sec)

root@localhost [mysql]> delete from db where user=‘test_user’;

Query OK, 1 row affected (0.00 sec)

So far, as commented above, MySQL isn’t aware that the user test_user was deleted (MySQL hasn’t re-read the grant tables into memory because they did not execute a FLUSH PRIVILEGES); that’s why when they tried to create the user again, it failed.

root@localhost [mysql]> CREATE USER ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’ WITH MAX_USER_CONNECTIONS 10;

ERROR 1396 (HY000): Operation CREATE USER failed for ‘test_user’@‘10.10.10.10’

And since they couldn’t find the user, they did what we would all do: Retry again and hope that the command would magically work this time.

root@localhost [mysql]> CREATE USER ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected (0.01 sec)

And it worked, the user got created, and everything was ok in the world again. Why did it work? Because with the first CREATE USER (even though the command failed), MySQL did a reload of the grant privileges.

Here’s what happened with the first CREATE:

  1. MySQL checks its in-memory table and finds that the user already exists.
  2. Rejects the new user because it can’t duplicate the user.
  3. MySQL reloads the in-memory tables (This happens regardless of whether it was successful).

So, even though the command failed, MySQL reloads the in-memory tables and the user test_user doesn’t exist (since the user was deleted manually before); that’s why the second CREATE was successful.

The second CREATE USER executes successfully, it goes to the binlog and to the replica.

Now, from the replica’s point of view so far it has replicated the DELETE statements and ONE CREATE USER, and back to where it all began, the error in the replica:

LAST_ERROR_MESSAGE: Worker 2 failed executing transaction ‘UUID:GTID’ at master binlog.0012345, end_log_pos 98765; Error ‘Operation CREATE USER failed for ‘test_user’@’10.10.10.10” on query. Default database: ‘mysql’. Query: ‘CREATE USER ‘test_user’@’10.10.10.10’ IDENTIFIED WITH ‘mysql_native_password’ AS ‘************”

With the things explained above, I think it’s easier to understand what happened here: This CREATE statement is the “first” since the first one in the primary failed, so that one didn’t reach the replica, so to “fix” this we only started the replication, and that did the trick, this time the CREATE worked because it already reloaded the in-memory tables.

Before finishing, I wanted to test a few more things to understand why sometimes a simple FLUSH PRIVILEGES works and why sometimes it’s necessary to DROP USER entirely; short answer: It depends on how “well” you manually manipulated the grant tables.

When FLUSH PRIVILEGES does the trick

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

mysql> CREATE USER test123@10.10.10.10;

Query OK, 0 rows affected (0.02 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test123’;

+——————+————-+

| user             | host        |

+——————+————-+

| test123          | 10.10.10.10 |

+——————+————-+

1 row in set (0.00 sec)

mysql> DELETE FROM mysql.user WHERE user=‘test123’;

Query OK, 1 row affected (0.01 sec)

mysql> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.01 sec)

mysql> CREATE USER test123@10.10.10.10;

Query OK, 0 rows affected (0.01 sec)

Since the create user only inserted in mysql.user, it was the only table where the user exists, so the flush privileges command was successful.

When FLUSH PRIVILEGES isn’t enough

There are many grant tables, so when manually deleting a user, it’s easy to miss one of them and lead to errors that FLUSH PRIVILEGES won’t solve.

mysql> CREATE USER test123@10.10.10.10;

Query OK, 0 rows affected (0.01 sec)

mysql> GRANT ALL PRIVILEGES ON test_db.* TO test123@10.10.10.10;

Query OK, 0 rows affected (0.00 sec)

The GRANT command inserts a record in mysql.db table as well

mysql> SELECT user,host FROM mysql.user WHERE user=‘test123’;

+———+————-+

| user    | host        |

+———+————-+

| test123 | 10.10.10.10 |

+———+————-+

1 row in set (0.00 sec)

mysql> SELECT user,host,db FROM mysql.db WHERE user=‘test123’;

+———+————-+———+

| user    | host        | db      |

+———+————-+———+

| test123 | 10.10.10.10 | test_db |

+———+————-+———+

1 row in set (0.00 sec)

Then if I manually delete, but only from mysql.user table, the record in mysql.db will be there until it’s cleaned.

mysql> DELETE FROM mysql.user WHERE user=‘test123’;

Query OK, 1 row affected (0.01 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test123’;

Empty set (0.00 sec)

mysql> SELECT user,host,db FROM mysql.db WHERE user=‘test123’;

+———+————-+———+

| user    | host        | db      |

+———+————-+———+

| test123 | 10.10.10.10 | test_db |

+———+————-+———+

1 row in set (0.00 sec)

So even if I try with the FLUSH command, I won’t be able to create the user (due to the user existing in mysql.db)

mysql> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.01 sec)

mysql> CREATE USER test123@10.10.10.10;

ERROR 1396 (HY000): Operation CREATE USER failed for ‘test123’@‘10.10.10.10’

mysql> CREATE USER test123@10.10.10.10;

ERROR 1396 (HY000): Operation CREATE USER failed for ‘test123’@‘10.10.10.10’

mysql> CREATE USER test123@10.10.10.10;

ERROR 1396 (HY000): Operation CREATE USER failed for ‘test123’@‘10.10.10.10’

The proper way to do this is by executing the DROP command and letting MySQL clean whatever tables are required (You can see below that the mysql.db table was cleaned as well).

mysql> DROP USER test123@10.10.10.10;

Query OK, 0 rows affected (0.01 sec)

mysql> SELECT user,host,db FROM mysql.db WHERE user=‘test123’;

Empty set (0.00 sec)

And now the CREATE works:

mysql> CREATE USER test123@10.10.10.10;

Query OK, 0 rows affected (0.00 sec)

What about “IF NOT EXISTS” clause?

Using the same scenario with replication; first, create the user in the primary.

mysql> CREATE USER ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY  ‘<redacted>’;

Query OK, 0 rows affected (0.00 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test_user’;

+————+————-+

| user      | host        |

+————+————-+

| test_user | 10.10.10.10 |

+————+————-+

1 row in set (0.00 sec)

After this, manually delete the user from the mysql.user table.

mysql> DELETE FROM mysql.user WHERE user=‘test_user’;

Query OK, 1 row affected (0.00 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test_user’;

Empty set (0.00 sec)

We know that a CREATE USER command would fail and reload the in-memory tables; let’s see what happens if we add the IF NOT EXISTS clause:

mysql> CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected, 1 warning (0.00 sec)

No errors, but one warning:

mysql> SHOW WARNINGS;

+——-+——+————————————————————+

| Level | Code | Message                                                    |

+——-+——+————————————————————+

| Note  | 3163 | Authorization ID ‘test_user’@‘10.10.10.10’ already exists. |

+——-+——+————————————————————+

1 row in set (0.00 sec)

And the user doesn’t exist, as expected (It was manually deleted, but without FLUSH PRIVILEGES so MySQL is not aware).

mysql> SELECT user,host FROM mysql.user WHERE user=‘test_user’;

Empty set (0.00 sec)

But, this time the command was logged in the binlog:

mysql> SHOW BINLOG EVENTS IN ‘mysql-bin.000001’ FROM 2395 LIMIT 2G

*************************** 1. row ***************************

Log_name: mysqlbin.000001

Pos: 2395

Event_type: Gtid

Server_id: 1

End_log_pos: 2474

Info: SET @@SESSION.GTID_NEXT= ‘83988545-3051-11ed-b2af-0a3d309b4fdf:8’

*************************** 2. row ***************************

Log_name: mysqlbin.000001

Pos: 2474

Event_type: Query

Server_id: 1

End_log_pos: 2712

Info: use `mysql`; CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ IDENTIFIED WITH ‘mysql_native_password’ AS ‘<redacted>’ /* xid=68 */

2 rows in set (0.00 sec)

And was replicated without issues as well, below are the relay log events:

mysql> SHOW RELAYLOG EVENTS IN ‘relay-log-server.000002’ FROM 2611G

*************************** 1. row ***************************

Log_name: relaylogserver.000002

Pos: 2611

Event_type: Gtid

Server_id: 1

End_log_pos: 2474

Info: SET @@SESSION.GTID_NEXT= ‘83988545-3051-11ed-b2af-0a3d309b4fdf:8’

*************************** 2. row ***************************

Log_name: relaylogserver.000002

Pos: 2690

Event_type: Query

Server_id: 1

End_log_pos: 2712

Info: use `mysql`; CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ IDENTIFIED WITH ‘mysql_native_password’ AS ‘<redacted>’ /* xid=68 */

Last thing to keep in mind, this time the Account Management Statement didn’t reload the grant tables after execution (We can know this because the second execution didn’t create the user, as happens when the CREATE USER  is executed without the clause, see the warnings below):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

mysql> CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test_user’;

Empty set (0.00 sec)

mysql> FLUSH PRIVILEGES;

Query OK, 0 rows affected (0.00 sec)

mysql> CREATE USER IF NOT EXISTS ‘test_user’@‘10.10.10.10’ identified WITH ‘mysql_native_password’ BY ‘<redacted>’;

Query OK, 0 rows affected (0.01 sec)

mysql> SELECT user,host FROM mysql.user WHERE user=‘test_user’;

+————+————-+

| user      | host        |

+————+————-+

| test_user | 10.10.10.10 |

+————+————-+

1 row in set (0.00 sec)

So, the IF NOT EXISTS clause can save you from the error (and no issues in a replication environment as well), but as always, be sure to check the warnings to understand what’s happening, otherwise, you’ll still don’t have the user required.

Final thoughts

You should definitely use the Account Management Statements when you want to modify privileges/users in MySQL, so you don’t have to worry about all the details.

I wanted to share this particular scenario with you in the hopes that this will make clearer how MySQL manages internal privileges and that the in-memory tables are a critical thing to have in mind should you modify anything manually.

And finally, remember that the docs are your friend:

If you modify the grant tables directly using statements such as INSERT, UPDATE, or DELETE (which is not recommended), the changes have no effect on privilege checking until you either tell the server to reload the tables or restart it. Thus, if you change the grant tables directly but forget to reload them, the changes have no effect until you restart the server. This may leave you wondering why your changes seem to make no difference!

I just tried to add a new user to MySQL using

CREATE USER 'name'@'%' IDENTIFIED BY '...'

However, it fails with the following error:

ERROR 1396 (HY000): Operation CREATE USER failed for 'name'@'%'

Adding the user just for localhost works fine:

CREATE USER 'name'@'localhost' IDENTIFIED BY '...'

I have no clue what could be the problem. I’d be grateful for any ideas.

(I’m using mysql Ver 14.14 Distrib 5.1.66.)

asked Feb 18, 2013 at 13:17

Petr's user avatar

1

According to the docs if you ommit the @’hostname’ (that is CREATE USER ‘name’) MySQL will interpret it as it had a @’%’. The error message you provided suggests that there is already a user ‘name’@’%’ in the system:

mysql> CREATE USER 'name'@'%' IDENTIFIED BY 'test';
Query OK, 0 rows affected (0.04 sec)

mysql> CREATE USER 'name'@'%' IDENTIFIED BY 'test';
ERROR 1396 (HY000): Operation CREATE USER failed for 'name'@'%'
mysql> CREATE USER 'name' IDENTIFIED BY 'test';
ERROR 1396 (HY000): Operation CREATE USER failed for 'name'@'%'

If you delete the user and still get the message, try running FLUSH PRIVILEGES.

Also see this SO question for additional info.

Community's user avatar

answered Feb 18, 2013 at 13:27

redguy's user avatar

redguyredguy

9666 silver badges13 bronze badges

I was facing this same error while using mysql:5.7 docker image. Main mistake was trying to create root user which exists by default.
More information: https://github.com/docker-library/mysql/issues/129

As given in the above link, solution was to NOT set MYSQL_USER and MYSQL_PASSWORD in the environment variables while starting the docker image.

answered May 27, 2018 at 5:31

rahuljain1311's user avatar

1

Понравилась статья? Поделить с друзьями:
  • Sql error 42704
  • Spyhunter ошибка вызова функции скрипта установки
  • Sql error 42703 ошибка столбец не существует
  • Spyhunter 5 ошибка при создании скрипта конфигурации установки
  • Sql error 42703 error column does not exist