Strange MySQL error "Empty row packet body" when using mysql_fetch_object (PHP 5.3.3)

I ran into the same error. I was using PDO, but it should basically be the same thing.

Are you operating on a MyISAM table? If so, the problem is probably related to the locking model this Engine uses: it locks the whole table, for reading with a shared lock, for writing with an exclusive lock.

This is what I was trying to do: Read a large result set unbuffered, and update some of the rows in the same table. Since you can't issue a statement on the same connection while it holds an unbuffered result set, I tried using another connection for the updates. Reading went well until the first update, at which point the script stalled for about a minute, then I got the "Empty row packet body" error.

You see, when reading unbuffered, the shared lock is kept until the whole result set has been read or the cursor is being closed. During that time, the table is locked with a shared lock, so other connections can obtain shared locks on the table (in other words, read from it), but exclusive locks (for writing) will have to wait. If this happens within the same script, it will deadlock.

Now, to prevent endless deadlocking, MySQL will forcibly release your shared lock after a while (IIRC this is affected by the value of table_lock_wait_timeout), dumping your result set and allowing the writing statement with the waiting exclusive lock to get its turn.

So, while in my case it was the same script that did this and therefore stalled until the timeout expired, it might also be that some other script is attempting a write operation on the table with the same effect, which is probably what happened in your case.

What solved the problem for me was changing the table type to InnoDB, since that Engine uses row-level instead of table-level locks. However, since you say the database is not yours, this might not be possible for you.


The actual issue is that the connection between PHP and MySQL was broken (=stopped before all data were received by PHP).

When PHP (PDO) does a MySQL Query, it sends the query on the opened connection, then waits for the response. The response consists of a set of headers, and a body, somehow like an HTTP request.

In case the connection is broken while PDO hasn't received all headers, then you will get a Warning "Error reading result set's header", meaning that PDO cannot interpret the response, since it's partial (headers) only.

If the connection is broken while the body is being parsed, then, PDO will yield a "Empty row packet body", corresponding to your error. See this Github PR for additionnal infos

So the fix is to find why the connection was killed:

  • Was it because connection timed out? Then try fixing the configuration as suggeested
  • Was it because the connection got manually killed by `KILLè command? Then ask the killer to stop doing that
  • Was it because Mysql memory got full and your instance got killed by your web hosting? Then reduce the resultset size/get a bigger MySQL server/ask for more RAM
  • Was it because a "deadlock" occured, so Mysql arbitrarily killed a connection (more likely to happen with MyISAM tables, including internal temporary ones)? Then try using InnoDB
  • Was it because the hardward connection got interrupted, like a bad wire/wifi reception between PHP and MySQL? Then fix the hardware.
  • Was it because a dump program asked to kill all connections for processing the dump? Then wait for the existing connections to finish before running the dump

Having this error a while a ago, I've fixed it by increasing the value of

net_read_timeout = 360
net_write_timeout = 360

While a connection is open on write, waiting for another query to end to continue inserting, this times out, giving an empty row packet. I'm working on very large dataset, used value are over 360. Your value will depend on your use case.

Tags:

Mysql

Php

Php 5.3