How to Restrict a MySQL Account to One Host or Network
In MySQL, an account isn't just a name: it's a name and where it may connect from. Narrow that part, and a stolen password is useless from anywhere else.
Security Practices and Solutions
View All TagsIn MySQL, an account isn't just a name: it's a name and where it may connect from. Narrow that part, and a stolen password is useless from anywhere else.
MySQL's max_connections limits the whole server, so one app with a runaway pool can lock everyone else out. MAX_USER_CONNECTIONS puts a ceiling on one account, so that its problem stays its own.
Change an app's MySQL password the plain way, and there's a gap between the server's change and the app's. With RETAIN CURRENT PASSWORD, MySQL accepts both for as long as you need, so there's no gap at all.
An app shouldn't be able to change tables, but migrations have to. So they get their own account. To find exactly which rights it needs, I applied a real set of EF Core migrations to an empty database, taking away one right each time.
REVOKE takes a right away, and you don't need FLUSH PRIVILEGES after it. The surprise is timing: a session that's already open can keep a database-level right until it next runs USE. I tested it in two sessions, and with a running app.
Your app reads and changes rows. It doesn't need to drop tables, and if it can't, then neither can a bug in it or an injected query. Here's an account with exactly those four rights, on one database.
Before you change an account's rights, or wonder why something's refused, ask MySQL what the account can do. SHOW GRANTS answers in a line or two, once you know how to read them.
MySQL 9.7 accepts TLS 1.2 and 1.3 by default. To allow only 1.3, one setting and one reload do it, with no restart. Before you do, check your clients: MySql.Data for .NET asks for TLS 1.2 unless you tell it otherwise, so it would stop connecting.
REQUIRE X509 adds a second factor to a MySQL account: as well as the password, it must present a certificate signed by the server's CA. The mysql client handles this well. .NET's MySql.Data has a catch, and it's in here too.
To make one MySQL account use TLS, whatever the others do, add REQUIRE SSL. It's stricter than the server-wide setting: a local socket isn't good enough, and the refusal gives no reason, so know both before you turn it on.