diff --git a/django/test/simple.py b/django/test/simple.py
index c9adfd2..7e722cd 100644
--- a/django/test/simple.py
+++ b/django/test/simple.py
@@ -1,3 +1,4 @@
+import threading
 import unittest as real_unittest
 
 from django.conf import settings
@@ -252,6 +253,9 @@ class DjangoTestSuiteRunner(object):
         return reorder_suite(suite, (TestCase,))
 
     def setup_databases(self, **kwargs):
+        # Record existing threads, so that we can check for threads created
+        # during testing before tearing down databases. See #10868.
+        self._record_threads()
         from django.db import connections, DEFAULT_DB_ALIAS
 
         # First pass -- work out which databases actually need to be created,
@@ -311,6 +315,10 @@ class DjangoTestSuiteRunner(object):
         return unittest.TextTestRunner(verbosity=self.verbosity, failfast=self.failfast).run(suite)
 
     def teardown_databases(self, old_config, **kwargs):
+        # Check that there are no alive threads left behind from the tests.
+        # If these would sprung to life, they would access the production DB.
+        # see #10868.
+        self._check_alive_threads()
         from django.db import connections
         old_names, mirrors = old_config
         # Point all the mirrors back to the originals
@@ -356,3 +364,29 @@ class DjangoTestSuiteRunner(object):
         self.teardown_databases(old_config)
         self.teardown_test_environment()
         return self.suite_result(suite, result)
+
+    def _get_thread_ident(self, thread):
+        """
+        Get an identifier for the given thread.
+
+        Python 2.5 doesn't have thread.ident, so use thread.name if ident
+        doesn't exists.
+        """
+        try:
+            return thread.ident
+        except AttributeError:
+            return thread.name
+
+    def _check_alive_threads(self):
+        for thread in threading.enumerate():
+            if self._get_thread_ident(thread) not in self._pre_test_threads:
+                thread.join(timeout=1.0)
+                if thread.is_alive():
+                    raise RuntimeError(
+                        "Thread (name=%s) still alive after tests.",
+                        thread.name)
+
+    def _record_threads(self):
+        self._pre_test_threads = set()
+        for thread in threading.enumerate():
+            self._pre_test_threads.add(self._get_thread_ident(thread))
diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt
index f614dee..c4d8442 100644
--- a/docs/releases/1.4.txt
+++ b/docs/releases/1.4.txt
@@ -995,3 +995,10 @@ useful, it was removed in Django 1.4. If you relied on it, you must edit your
 settings file to list all your applications explicitly.
 
 .. _this can't be done reliably: http://docs.python.org/tutorial/modules.html#importing-from-a-package
+
+Threads created during testing must be also closed during testing
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To make sure test threads will not access the production database (or
+otherwise create havoc after tests) Django now enforces that threads created
+during testing must not be alive after the tests have ran.
diff --git a/tests/regressiontests/test_runner/tests.py b/tests/regressiontests/test_runner/tests.py
index 4e2555e..4dd04f4 100644
--- a/tests/regressiontests/test_runner/tests.py
+++ b/tests/regressiontests/test_runner/tests.py
@@ -5,13 +5,16 @@ from __future__ import absolute_import
 
 import StringIO
 from optparse import make_option
+import time
+from threading import Thread
 import warnings
 
 from django.core.exceptions import ImproperlyConfigured
 from django.core.management import call_command
 from django.test import simple
 from django.test.simple import get_tests
-from django.test.utils import get_warnings_state, restore_warnings_state
+from django.test.utils import (get_warnings_state, restore_warnings_state,
+                               override_settings)
 from django.utils import unittest
 from django.utils.importlib import import_module
 
@@ -225,3 +228,73 @@ class ModulesTestsPackages(unittest.TestCase):
         "Test for #12658 - Tests with ImportError's shouldn't fail silently"
         module = import_module(TEST_APP_ERROR)
         self.assertRaises(ImportError, get_tests, module)
+
+class Condition(object):
+    def __init__(self):
+        self._break = False
+
+def waiter_thread(condition):
+    while True:
+        if condition._break:
+            break
+        time.sleep(0.1)
+
+
+class ThreadsTest(unittest.TestCase):
+    """
+    Test that all threads created while running the tests are gone before
+    tearing down the testing databases. Refs: #10868.
+
+    The tests target _record_threads and _check_alive_threds, because actually
+    running teardown_databases seems a little problematic.
+    """
+    def test_threads_left_alive(self):
+        """
+        Check that there is an error if there are threads left alive after tests.
+        """
+        dj = simple.DjangoTestSuiteRunner()
+        dj._record_threads()
+        condition = Condition()
+        t = Thread(target=waiter_thread, args=(condition,))
+        t.start()
+        with self.assertRaises(RuntimeError):
+            dj._check_alive_threads()
+        condition._break = True
+        t.join()
+
+    def test_threads_created_before(self):
+        """
+        Check that threads started before testing are allowed to exist also
+        after tests.
+        """
+        condition = Condition()
+        t = Thread(target=waiter_thread, args=(condition,))
+        t.start()
+        dj = simple.DjangoTestSuiteRunner()
+        dj._record_threads()
+        try:
+            dj._check_alive_threads()
+        except RuntimeError:
+            self.assertFalse(True) # Should not raise this error!
+        condition._break = True
+        t.join()
+
+    def test_threads_mixed(self):
+        """
+        Check that if there are threads created before tests, and threads left
+        alive during testing, there is an error.
+        """
+        condition1 = Condition()
+        condition2 = Condition()
+        t1 = Thread(target=waiter_thread, args=(condition1,))
+        t1.start()
+        dj = simple.DjangoTestSuiteRunner()
+        dj._record_threads()
+        t2 = Thread(target=waiter_thread, args=(condition2,))
+        t2.start()
+        with self.assertRaises(RuntimeError):
+            dj._check_alive_threads()
+        condition1._break = True
+        condition2._break = True
+        t1.join()
+        t2.join()
