Creating an application user used to be one GRANT with IDENTIFIED BY. On MySQL 8 that path fails with ERROR 1410 (42000): You are not allowed to create a user with GRANT. You create the account first, then attach privileges, and a desktop GUI can run both steps without you memorizing the syntax.
Why GRANT no longer creates the account
MySQL 8 split account management. CREATE USER defines the name, host, and password. GRANT only attaches privileges to an account that already exists. MariaDB follows the same CREATE-then-GRANT pattern on current releases. If you paste an old snippet that combines both jobs, the server rejects it even when you are connected as root.
A client that still looks like “create user from GRANT” is wrapping CREATE USER under the hood, or it is talking to MySQL 5.7. Workbench, phpMyAdmin, HeidiSQL, and TabulaSQL all end up issuing the two statements. The difference is whether you click through a form or type SQL.
You still need an admin session. The app user you are about to create cannot add itself.
Connect as someone who can read mysql.user
Open a connection as root, or as a dedicated DBA login with CREATE USER plus the right to GRANT. Default port is 3306. Local Docker and Laravel Herd still need that admin connection, even when the application uses 127.0.0.1.
TabulaSQL is a free desktop client for MySQL, MariaDB, PostgreSQL, and SQLite. The user manager is MySQL and MariaDB only. Open the MySQL connection, then press Ctrl+P (Cmd+P on Mac) and choose Manage MySQL users. You can also right-click the connection in the sidebar and pick Manage Users. The panel title is MySQL users & privileges. If the list is empty and you see Cannot read mysql.user, the current login cannot query the grant tables.
Keep production connections color-coded. Turn Safe Lock on before you drop anyone. Dropping a user is immediate and asks for confirmation.
Create the account, then pick the host
Click New user. Fill in three fields:
- User: the login name, for example
shop_app. Do not reuseroot. - Host: where this account may connect from. The form defaults to
%. - Password: a real secret, not the schema name.
Click Create. TabulaSQL runs CREATE USER 'shop_app'@'%' IDENTIFIED BY '...'. The account now exists with USAGE only. That is enough to authenticate and not enough to read your tables.
Host is part of the identity. 'shop_app'@'localhost' and 'shop_app'@'%' are two different rows. On Linux and macOS, localhost often means a Unix socket. A GUI on the same machine usually connects over TCP to 127.0.0.1, which matches % or 127.0.0.1, not localhost. If you only create @'localhost' and then fail from TabulaSQL, HeidiSQL, or Workbench, add an account for 127.0.0.1 instead of widening privileges on root.
| How you connect | Host that usually matches |
|---|---|
| TCP to 127.0.0.1 (most GUIs, Docker published on 3306) | 127.0.0.1 or % |
| mysql CLI via Unix socket | localhost |
| Remote laptop or another container | % or a hostname pattern |
Prefer a tight host when you can: 127.0.0.1 for local Docker, a bastion hostname, or %.internal.example.com. Keep % for laptops that move, and pair it with a least-privilege database grant.
Grant on one database, then read SHOW GRANTS
Select the new user@host row. The right pane shows SHOW GRANTS output, usually GRANT USAGE ON *.* TO 'shop_app'@'%'. Under Grant on database:
- Type the database name, for example
shop. - Leave privileges as
SELECT, INSERT, UPDATE, DELETEunless the job needs more. - Click Grant.
That issues GRANT SELECT, INSERT, UPDATE, DELETE ON \shop`.* TO 'shop_app'@'%'`. The grant list refreshes so you can confirm the line. The panel accepts CREATE, DROP, INDEX, ALTER, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, TRIGGER, and ALL PRIVILEGES. Do not grant PROCESS or SHOW DATABASES to an application user unless you have a reason.
Workbench puts the same work under Administration, Users and Privileges. phpMyAdmin uses User accounts. Those screens expose more global checkboxes, which is useful for a DBA login and noisy for an app login. Default to database-level DML, then add CREATE or ALTER only for migration users.
CREATE USER and GRANT update the grant tables themselves. You do not need FLUSH PRIVILEGES after those statements. Some clients still run it. That is harmless, not required.
Test the login before you ship credentials
Duplicate the admin connection in the sidebar. Change username and password to shop_app. Set host to the value the app will use (127.0.0.1 for Docker on 3306). Click Test connection, then save. Open the object tree: you should see shop and not every database on the instance.
Run a SELECT and a small UPDATE in the editor. If writes fail with a privilege error, the grant never landed on that user@host pair. If authentication fails while the mysql CLI works, check the plugin column next to the account (often caching_sha2_password on MySQL 8) and follow Fix MySQL 8 caching_sha2_password in a GUI.
When you outgrow checkboxes, paste SQL in the editor:
CREATE USER 'shop_app'@'127.0.0.1' IDENTIFIED BY 'replace-me';
GRANT SELECT, INSERT, UPDATE, DELETE ON `shop`.* TO 'shop_app'@'127.0.0.1';
SHOW GRANTS FOR 'shop_app'@'127.0.0.1';
Safe Lock previews writes if you enable it. Keep the GUI for listing accounts. Use the editor for WITH GRANT OPTION, roles, or resource limits that the panel does not expose.
If you want that user manager on Mac, Windows, or Linux without installing phpMyAdmin, grab TabulaSQL from https://tabulasql.com/download. For leaving a browser admin behind, see phpMyAdmin desktop alternative.