Skip to content
HackIndex logo

HackIndex

MySQL FILE Privilege Detection

3 min read Mar 26, 2026

The FILE privilege in MySQL allows a user to read files from the server filesystem using LOAD_FILE() and write files using SELECT ... INTO OUTFILE or SELECT ... INTO DUMPFILE. On a web server where MySQL runs with sufficient OS permissions, FILE privilege enables reading sensitive files like /etc/passwd and writing webshells to the web root. It is one of the most impactful misconfigurations in a MySQL deployment and is frequently present on over-provisioned application database accounts.

Check Current User Grants

The fastest check once connected is to inspect the grants for the current user:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SHOW GRANTS FOR CURRENT_USER();"
+---------------------------------------------------------------------------+
| Grants for app@%                                                          |
+---------------------------------------------------------------------------+
| GRANT SELECT, INSERT, UPDATE, DELETE, FILE ON *.* TO 'app'@'%'           |
+---------------------------------------------------------------------------+

FILE appearing in the grant list confirms the privilege is held. Even on a non-root account, FILE privilege enables reading any file the MySQL process user can access and writing to any directory the process user can write to.

Query the Privilege Directly

Check the mysql.user table for the FILE column on the current account:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT user, host, File_priv FROM mysql.user WHERE user = CURRENT_USER();"
+------+------+-----------+
| user | host | File_priv |
+------+------+-----------+
| app  | %    | Y         |
+------+------+-----------+

File_priv = Y confirms FILE privilege. If the mysql.user table is not accessible with the current account, use the SHOW GRANTS approach instead.

Confirm with a Safe Read Test

Verify FILE privilege is actually functional by reading a file that is always readable:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/hostname');"
+-------------------------+
| LOAD_FILE('/etc/hostname') |
+-------------------------+
| webserver01             |
+-------------------------+

A non-null result confirms LOAD_FILE is working. A NULL result despite the privilege being present usually means the secure_file_priv variable is restricting the read path. Check it:

┌──(kali㉿kali)-[~]
└─$ mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SHOW VARIABLES LIKE 'secure_file_priv';"
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| secure_file_priv |       |
+------------------+-------+

An empty value for secure_file_priv means no path restriction is in place — LOAD_FILE and INTO OUTFILE can reach any path the MySQL process user can access. A specific path value restricts operations to that directory. A value of NULL disables file operations entirely regardless of FILE privilege.

Check the MySQL Process User on the Host

The FILE privilege operates with the permissions of the OS user running MySQL. On Linux this is typically mysql but on misconfigured systems it may be root. If you have shell access confirm:

┌──(kali㉿kali)-[~]
└─$ ps aux | grep mysqld
mysql    1482  0.5  4.2 1234567 87654 ?  Sl   09:12   0:42 /usr/sbin/mysqld

MySQL running as root combined with FILE privilege and no secure_file_priv restriction means the account can read any file on the system and write to any directory. This is the highest-severity FILE privilege configuration and enables direct webshell deployment to the web root. Exploitation is covered in the FILE read and INTO OUTFILE pages.

References