<?xml version="1.0" ?><entry xml:lang="en" xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/"><id>http://price.mit.edu/blog/?p=177</id><link href="http://price.mit.edu/blog/2010/06/killing-a-mysql-query/" rel="alternate" type="text/html"/><title>Preventing SQL Undeath (Killing a MySQL Query For Real)</title><summary>Sometimes a MySQL query doesn’t die when you think it does.
If you’ve spent much time with MySQL, you’ve probably tried a query from the mysql command line, changed your mind after it didn’t return for a while, and hit C-c:

$ mysql -h youtomb-sql.mit.edu -u guest youtomb

mysql&gt; SELECT COUNT(DISTINCT status) FROM artifacts;
^CCtrl-C -- sending &quot;KILL QUERY [...]</summary><content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Sometimes a MySQL query doesn’t die when you think it does.</p>
<p>If you’ve spent much time with MySQL, you’ve probably tried a query from the <code>mysql</code> command line, changed your mind after it didn’t return for a while, and hit C-c:</p>
<pre>$ mysql -h <a href="http://youtomb.mit.edu/blog/">youtomb-sql.mit.edu</a> -u guest youtomb

mysql&gt; SELECT COUNT(DISTINCT status) FROM artifacts;
^CCtrl-C -- sending &quot;KILL QUERY 183&quot; to server ...
Ctrl-C -- query aborted.
ERROR 1317 (70100): Query execution was interrupted
</pre>
<p/>
<p>That kills the query.  But notice what the <code>mysql</code> program is telling you after you hit that C-c: it’s sending a <em>separate command</em>, namely the “query” “<code>KILL QUERY 183</code>“, to the server.</p>
<p>In fact, that <a href="http://dev.mysql.com/doc/refman/5.1/en/kill.html"><code>KILL</code> query</a> is the only way to get the MySQL server to stop running a query.  In particular, the MySQL server is really bad at noticing when a client goes away.  Suppose instead of hitting C-c, which the <code>mysql</code> program traps and handles in a smart way, I simply kill the program by hitting <a href="http://en.wikipedia.org/wiki/SIGQUIT">C-\</a>:</p>
<pre>mysql&gt; SELECT COUNT(DISTINCT status) FROM artifacts;
^\Aborted
</pre>
<p/>
<p>Then in fact the server keeps running the query.  If I fire up the MySQL client anew and issue the query <a href="http://dev.mysql.com/doc/refman/5.1/en/show-processlist.html"><code>SHOW PROCESSLIST</code></a>, I can see the query still chugging away:</p>
<pre>$ mysql -h youtomb-sql.mit.edu -u guest youtomb

mysql&gt; SHOW PROCESSLIST \G
*************************** 1. row ***************************
     Id: 183
   User: guest
   Host: OPUS.MIT.EDU:37938
     db: youtomb
Command: Query
   Time: 4
  State: Sending data
   Info: SELECT COUNT(DISTINCT status) FROM artifacts
*************************** 2. row ***************************
     Id: 185
   User: guest
   Host: OPUS.MIT.EDU:37940
     db: youtomb
Command: Query
   Time: 0
  State: NULL
   Info: SHOW PROCESSLIST
2 rows in set (0.00 sec)
</pre>
<p/>
<p>That <code>\G</code> is an <a href="http://dev.mysql.com/doc/refman/5.1/en/mysql-commands.html#id2848319">alternative to the semicolon</a> that makes the format more readable here.</p>
<p>If I want to actually kill the query, I can do it with the same meta-query my client used automatically upon C-c:</p>
<pre>mysql&gt; KILL QUERY 183;
Query OK, 0 rows affected (0.02 sec)
</pre>
<p/>
<p>Et voilà:</p>
<pre>mysql&gt; SHOW PROCESSLIST \G
*************************** 1. row ***************************
     Id: 185
   User: guest
   Host: OPUS.MIT.EDU:37940
     db: youtomb
Command: Query
   Time: 0
  State: NULL
   Info: SHOW PROCESSLIST
1 row in set (0.00 sec)
</pre>
<p/>
<p>Now, why would you or I care?  After all, nobody in their right mind goes about hitting control-backslash or employing equally messy means to kill their MySQL clients.  And control-C behaves just as you’d hope — so long as you are using the <code>mysql</code> command-line client.</p>
<p>Where the story isn’t so good is on a typical other client program.  The <code>KILL</code> behavior on control-C is a feature of the <code>mysql</code> program, not of the MySQL C API.  (If you think about it, it involves installing a signal handler — not something a well-behaved library will just do.)  And because it’s not a feature of the MySQL C API, it’s probably not a feature of your favorite language’s MySQL bindings, which wrap that API.  In particular, I know it’s not a feature of <a href="http://mysql-python.sourceforge.net/">MySQLdb</a>, the leading Python bindings.</p>
<p>So suppose you write a Python script to do some MySQL queries… and you have a big honking table in your database, and you write an inefficient query… and the query planner resorts to copying most of the table to a temporary table… and after a couple of hours you kill the Python script with control-C or <code>kill</code> or some other means because it’s taking forever.  The query will keep running.  And the next day maybe it’s copied enough that it fills up your disk, and the database has an outage.</p>
<p>I wish that were a hypothetical.  Fortunately, the MySQL server will then remove the temporary table and the disk will have space again.  If you’re lucky, the server will even come back up.</p>
<p><strong>Lesson</strong>: when you want to kill a MySQL query, make sure it dies.  Use <code>SHOW PROCESSLIST</code> to check and <code>KILL QUERY</code> to kill.</p></div></content><updated planet:format="June 28, 2010 04:35 AM">2010-06-28T04:35:37Z</updated><category term="Uncategorized"/><category term="howto"/><category term="mysql"/><category term="sipb"/><author><name>Greg Price</name></author><source><id>http://price.mit.edu/blog</id><link href="http://price.mit.edu/blog/tag/sipb/feed/" rel="self" type="application/rss+xml"/><link href="http://price.mit.edu/blog" rel="alternate" type="text/html"/><title>price.mit.edu/blog » sipb</title><updated planet:format="January 25, 2026 03:07 AM">2026-01-25T03:07:27Z</updated><planet:format>rss20</planet:format><planet:http_etag>&quot;452a10c017d6ace36ea6c313eb650a31&quot;</planet:http_etag><planet:http_last_modified>Mon, 16 Aug 2010 16:26:14 GMT</planet:http_last_modified><planet:bozo>false</planet:bozo><planet:encoding>utf-8</planet:encoding><planet:css-id>gregory-price</planet:css-id><planet:items_per_page>60</planet:items_per_page><planet:name>Gregory Price</planet:name><planet:days_per_page>0</planet:days_per_page><planet:http_status>200</planet:http_status></source></entry>