Bug #120227 LOAD DATA LOCAL INFILE: missing EOF packet on IOException leaves server thread hanging
Submitted: 7 Apr 15:05 Modified: 28 Jul 20:59
Reporter: robi su Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:9.6.0 OS:Any
Assigned to: Filipe Silva CPU Architecture:Any
Tags: load-data, local-infile, protocol

[7 Apr 15:05] robi su
Description:
When an IOException occurs while reading file data during LOAD DATA LOCAL INFILE (e.g. due to a network interruption or a stream read failure), NativeProtocol.sendFileToServer() throws the exception back to the caller but never sends the empty EOF packet that terminates the file transfer.

The MySQL protocol requires an empty packet to signal end-of-file to the server. Without it, the server thread stays in "executing" state, still waiting for more file data. It will remain blocked until net_read_timeout fires (default 30 seconds).

Meanwhile the JDBC connection is left in a broken state — any follow-up query on the same connection fails with "Got packets out of order" because the server is still processing the previous LOAD DATA command.

The MySQL C client (libmysql.cc, handle_local_infile) correctly sends the empty packet on error before returning.

Tested with Connector/J 9.6.0 against MySQL 9.3.0. The same code exists in 8.0.33 and 9.3.0.

How to repeat:
How to repeat:

Start MySQL with local_infile enabled:
docker run -d --name mysql-test -p 3306:3306 -e MYSQL_ALLOW_EMPTY_PASSWORD=1 mysql:9.3 --local-infile=1

Clone and run the minimal reproduction:
https://github.com/moonsphere/cj-loaddata-ioexception-bug.git (or attach the zip)
cd cj-loaddata-ioexception-bug && mvn compile exec:java

The test uses setLocalInfileInputStream() with a custom InputStream that throws IOException after sending ~100KB. It then checks the server PROCESSLIST and tries a follow-up query.

Output:

Test 1: IOException caught as expected
Test 2: Server thread shows Command=Query, State=executing, Info=LOAD DATA... (still waiting)
Test 3: Follow-up SELECT 1 fails with "Got packets out of order"

Suggested fix:
In NativeProtocol.sendFileToServer(), add an empty EOF packet send in the 

```java
catch(IOException) block before rethrowing:

} catch (IOException ioEx) {
    // Send empty EOF packet so the server can end LOAD DATA cleanly.
    try {
        filePacket.setPosition(0);
        send(filePacket, filePacket.getPosition());
        checkErrorMessage();
    } catch (Exception cleanupEx) {
        // Best-effort; original IOException takes priority.
    }

    // ...existing error message building and rethrow...
}
```

This matches the behavior of the MySQL C client (libmysql.cc handle_local_infile).
[13 Apr 23:15] Filipe Silva
Thank you for your interest in MySQL Connector/J and for taking the time file this report.

Verified as described.
[28 May 1:13] MySQL Admin
Posted by developer: Bug status updated to 'Documenting'
[28 Jul 20:59] Edward Gilmore
Posted by developer:
 
Added the following note to the MySQL Connector/J 26.7.0 release notes:		
 
If LOAD DATA LOCAL INFILE failed while reading the local source
        data, the client could exit without properly finishing the
        upload exchange with the server. In that situation, the original
        failure was reported to the application, but the server could
        remain waiting for the end of the transfer, which could leave
        the connection out of sync for the next command. 
        As of this release, the driver completes the cleanup path before returning the
        error. When a read-related failure happens, the driver now sends
        the end-of-file marker needed to finish the upload protocol and
        clears the server response as best effort, while still returning
        the original exception to the user. The handling was also
        adjusted so failures while closing the local input stream do not
        prevent that cleanup from happening.