Index: django/core/db/backends/mysql.py
===================================================================
--- django/core/db/backends/mysql.py	(revision 2360)
+++ django/core/db/backends/mysql.py	(working copy)
@@ -10,6 +10,7 @@
 from MySQLdb.converters import conversions
 from MySQLdb.constants import FIELD_TYPE
 import types
+import threading
 
 DatabaseError = Database.DatabaseError
 
@@ -47,14 +48,53 @@
         else:
             return getattr(self.cursor, attr)
 
+class ThreadLocal:
+    def __getattr__(self, key):
+        threadkey = 'ThreadLocal_%s' % (id(self),)
+        thread = threading.currentThread()
+        try:
+            local = getattr(thread, threadkey)
+            return local[key]
+        except AttributeError:
+            raise AttributeError(key)
+        except KeyError:
+            raise AttributeError(key)
+
+    def __setattr__(self, key, value):
+        threadkey = 'ThreadLocal_%s' % (id(self),)
+        thread = threading.currentThread()
+        try:
+            local = getattr(thread, threadkey)
+        except AttributeError:
+            local = {}
+            setattr(thread, threadkey, local)
+        local[key] = value
+
+    def __delattr__(self, key):
+        threadkey = 'ThreadLocal_%s' % (id(self),)
+        thread = threading.currentThread()
+        try:
+            local = getattr(thread, threadkey)
+            del local[key]
+        except AttributeError:
+            raise AttributeError(key)
+        except KeyError:
+            raise AttributeError(key)
+
 class DatabaseWrapper:
     def __init__(self):
-        self.connection = None
         self.queries = []
+        if hasattr(threading, 'local'):
+            # threading.local is available in Python 2.4 and later
+            self.threadlocal = threading.local()
+        else:
+            # workaround for Python 2.3 and earlier
+            self.threadlocal = ThreadLocal()
 
     def cursor(self):
         from django.conf.settings import DATABASE_USER, DATABASE_NAME, DATABASE_HOST, DATABASE_PORT, DATABASE_PASSWORD, DEBUG
-        if self.connection is None:
+        conn = getattr(self.threadlocal, 'connection', None)
+        if conn is None:
             kwargs = {
                 'user': DATABASE_USER,
                 'db': DATABASE_NAME,
@@ -64,28 +104,34 @@
             }
             if DATABASE_PORT:
                 kwargs['port'] = DATABASE_PORT
-            self.connection = Database.connect(**kwargs)
-        cursor = self.connection.cursor()
-        if self.connection.get_server_info() >= '4.1':
+            conn = self.threadlocal.connection = Database.connect(**kwargs)
+        else:
+            conn.ping()
+        cursor = conn.cursor()
+        if conn.get_server_info() >= '4.1':
             cursor.execute("SET NAMES utf8")
         if DEBUG:
             return base.CursorDebugWrapper(MysqlDebugWrapper(cursor), self)
         return cursor
 
     def commit(self):
-        self.connection.commit()
+        conn = getattr(self.threadlocal, 'connection', None)
+        if conn is not None:
+            conn.commit()
 
     def rollback(self):
-        if self.connection:
+        conn = getattr(self.threadlocal, 'connection', None)
+        if conn is not None:
             try:
-                self.connection.rollback()
+                conn.rollback()
             except Database.NotSupportedError:
                 pass
 
     def close(self):
-        if self.connection is not None:
-            self.connection.close()
-            self.connection = None
+        conn = getattr(self.threadlocal, 'connection', None)
+        if conn is not None:
+            conn.close()
+            self.threadlocal.connection = None
 
     def quote_name(self, name):
         if name.startswith("`") and name.endswith("`"):
