Skip to content
HackIndex logo

HackIndex

MySQL enumeration

4 min read Feb 11, 2026

Start by fingerprinting the server and auth behavior, then validate creds, then enumerate DB metadata and pull high-value tables. MySQL auth plugin and TLS requirements decide how you connect and what tooling will work.

Service discovery and banner

┌──(kali㉿kali)-[~]
└─$ nmap -sV -p ${PORT:-3306} $TARGET_IP
┌──(kali㉿kali)-[~]
└─$ nmap -p ${PORT:-3306} --script mysql-info $TARGET_IP

What you expect:

  • Server banner/version and protocol details.

  • If the host is reachable but MySQL is bound locally only, you’ll often see 3306 closed/filtered externally. You won’t enumerate further without another foothold or port exposure.

Quick weak-auth checks (no creds)

┌──(kali㉿kali)-[~]
└─$ nmap -p ${PORT:-3306} --script mysql-empty-password $TARGET_IP

Interpretation:

  • Any hit on root/anonymous with empty password is immediate priority. Move to interactive login and confirm privileges.

Broad NSE sweep (use with intent)

This is useful when you have creds and want a fast snapshot, but don’t shotgun everything by default.

┌──(kali㉿kali)-[~]
└─$ nmap -sV -p ${PORT:-3306} --script "mysql-info,mysql-databases,mysql-users,mysql-variables" $TARGET_IP

With creds:

┌──(kali㉿kali)-[~]
└─$ nmap -sV -p ${PORT:-3306} --script "mysql-databases,mysql-users,mysql-variables" --script-args mysqluser="$USER",mysqlpass="$PASSWORD" $TARGET_IP

Auth plugin and TLS edge cases (mysql_native_password vs caching_sha2)

Modern MySQL often uses caching_sha2_password. That can force TLS or require RSA key exchange, which changes your connection flags.

TLS required

If you see errors like “Authentication requires secure connection” or your org policy enforces TLS, connect with required SSL:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p --ssl-mode=REQUIRED
┌──(kali㉿kali)-[~]
└─$ # or disable SSL
┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p --ssl-mode=DISABLED
┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p --skip-ssl

caching_sha2_password and public key retrieval

If the server requires RSA key exchange and you’re not using TLS, the client may need to fetch the server public key:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p --get-server-public-key

If you already have the server key file:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p --server-public-key-path /path/to/public_key.pem

Interactive enumeration (mysql CLI)

Connect:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u "$USER" -p

Fast context:

SELECT VERSION();
SELECT @@@@version;
SELECT USER();
SELECT CURRENT_USER();
SELECT DATABASE();
SELECT @@@hostname;

What to do with it:

  • Version helps you judge old auth behavior, client compatibility, and whether legacy NSE checks are even relevant.

  • @@@hostname is useful for mapping the DB host to internal naming and environment.

Database, table, and column enumeration

SHOW DATABASES;
USE <database>;
SHOW TABLES;
DESCRIBE <table_name>;
SHOW COLUMNS FROM <table_name>;

Decision points:

  • Prioritize app-owned schemas over information_schema, performance_schema, sys, mysql.

  • Look for tables that usually carry secrets: users, accounts, auth, sessions, tokens, config, settings, oauth, api_keys.

User and privilege enumeration (when permitted)

List your effective grants first:

SHOW GRANTS FOR CURRENT_USER();

If you can read the mysql system schema:

SELECT user, host FROM mysql.user;
SELECT user, host, plugin FROM mysql.user;

What changes decisions:

  • FILE privilege enables file read/write primitives through MySQL features (this belongs to exploitation later, but it’s a key flag to capture now).

  • Broad grants on *.* usually means the account is operationally over-privileged.

High-signal server variables

If you want binding, paths, and auth defaults without trawling:

SHOW VARIABLES LIKE 'bind_address';
SHOW VARIABLES LIKE 'port';
SHOW VARIABLES LIKE 'datadir';
SHOW VARIABLES LIKE 'default_authentication_plugin';

Interpretation:

  • bind_address=127.0.0.1 or similar explains why you only see it via pivot/tunnel.

  • datadir and auth defaults are good context for later post-enum decisions.

Targeted data sampling

Pull a small slice from a candidate table before going wide:

SELECT * FROM <table_name> LIMIT 5;

If you suspect secrets in a column set:

SELECT <col1>, <col2> FROM <table_name> LIMIT 20;

What to do with results:

  • If you hit plaintext credentials/tokens, stop broad enumeration and pivot to impact-focused evidence capture with minimal queries.

Legacy and niche NSE scripts

mysql-enum relies on older auth behavior and is situational. If it’s not returning anything, don’t burn time on it; focus on creds and normal metadata paths.

mysql-vuln-cve2012-2122 is an auth-bypass check and is not passive enumeration.

mysql-vuln-cve2012-2122 actively attempts an auth bypass and may dump usernames/hashes. Run only with explicit approval.

┌──(kali㉿kali)-[~]
└─$ nmap -p ${PORT:-3306} --script mysql-vuln-cve2012-2122 $TARGET_IP

References