[Solved]-Why am I getting the "MySQL server has gone away" exception in Django?

8👍

I had exactly the same issue than yours. I implemented a monitoring script using watchdogs library, and, by the end of "wait_timeout", MySQL error would be raised.

After a few tries with "django.db.close_old_connections()" function, it still did not work, but I was attempting to close old connections every defined time interval, which was not working. I changed the close command to run only before the call of my custom management command (which is the command that will interact with db and used to crash with MySQL error) and it started to work.

Apparently from this page, the reason why that happen is because the "close_old_connection" function is linked only to HTTP request signals, so it will not be fired in specific custom scripts. The documentation of Django doesn’t tell that, and I honestly also understood things the same way you were understanding.

So, what you can try to do is to add the call to close old connection before interacting with db:

from django.db import close_old_connections
close_old_connections()
do_something_with_db()

0👍

In general, a connection should do its task, then disconnect. There is no good advantage in keeping a connection alive “forever”, which you seem to have.

It appears, as you noted, that a “timeout” has zapped your connection. (There are many timeouts; you discovered one of them.)

Even though you are able to increase the timeout, that would not be a complete solution. Other hiccups could happen, causing a disconnect.

Two solutions; do them both:

  • Connect, do the task, disconnect.
  • Check errors, if “gone away”, then reconnect.

0👍

I had the same problem just a few days ago, but without Django.
In my case, I was running a script forever, which would connect to the DB, then do its stuff, and to do a DB insert only when needed. Sometimes, the script needed to do its stuff for a days though, and as you stated, the default wait_timeout of MySQL is 28800 seconds or 8 hours.

I am not sure I understood your architecture properly, but I suspect something similar might be going on: You start your server, it connects to the DB (query #1), then you sleep one night (more than 8 hours), try to login (query #2), and voila, the connection has expired.

You can verify if this theory is correct in two easy ways:

1) set wait_timeout to 86400 (24 hours), do the same check you did from evening to morning by trying to login and you should be able to do so without an error.

2) set wait_timeout to a super small value, just a few seconds, and repeat the test – it should crash in a minute, not overnight.

Do not forget to restart MySQL after changing its params.

How did I solve the problem (without Django): Using a simple retry from the tenacity pack + connection restart before the retry.

How could you resolve it: Just found this Django plugin which is supposed to do exactly this. Never used it, but might be worth trying.

Note: While increasing the wait_timeout from MySQL could fix the problem, I wouldn’t go for it if I can fix it with such retries. Huge values might be dangerous as stalled connections may start to build up and result in another error: Too many connections.

0👍

I use two ways to avoid this problem:
The thorough way: Close all the django connections after each activity. Example:

from django.db import connection
    
something.save()
connection.close()

The quick (and dirty) way: Just modify the django model access where the program crashes (the first one after long inactivity). Example:

from django.db import connection
from django.db.utils import OperationalError  

while True:
  try:
    something.save()
    break
  except OperationalError:
    connection.close()

Leave a comment