diff --git a/django/db/__init__.py b/django/db/__init__.py
index b198048..548c2d5 100644
--- a/django/db/__init__.py
+++ b/django/db/__init__.py
@@ -42,8 +42,25 @@ backend = load_backend(connection.settings_dict['ENGINE'])
 # Register an event that closes the database connection
 # when a Django request is finished.
 def close_connection(**kwargs):
+    # Avoid circular imports
+    from django.db import transaction
     for conn in connections.all():
         conn.close()
+        # Make sure transaction_state isn't carried from one request to
+        # another. The weird structure here is caused by TestCase turning
+        # leave_transaction_management() to no-op.
+        tx_state_len = len(conn.transaction_state)
+        while tx_state_len:
+            try:
+                transaction.leave_transaction_management(using=conn.alias)
+            except transaction.TransactionManagementError:
+                # Even if we closed the connection above Django still thinks
+                # might be a transaction going on...
+                pass
+            if len(conn.transaction_state) == tx_state_len:
+                # It seems it was a no-op.
+                break
+            tx_state_len = len(conn.transaction_state)
 signals.request_finished.connect(close_connection)
 
 # Register an event that resets connection.queries
diff --git a/django/middleware/transaction.py b/django/middleware/transaction.py
index 96b1538..7888839 100644
--- a/django/middleware/transaction.py
+++ b/django/middleware/transaction.py
@@ -15,6 +15,7 @@ class TransactionMiddleware(object):
     def process_exception(self, request, exception):
         """Rolls back the database and leaves transaction management"""
         if transaction.is_dirty():
+            # This rollback might fail for closed connections for example.
             transaction.rollback()
         transaction.leave_transaction_management()
 
@@ -22,6 +23,21 @@ class TransactionMiddleware(object):
         """Commits and leaves transaction management."""
         if transaction.is_managed():
             if transaction.is_dirty():
-                transaction.commit()
+                # Note: it is possible that the commit fails. If the reason is
+                # closed connection or some similar reason, then there is
+                # little hope to proceed nicely. However, in case of deferred
+                # foreign key check failures we can still rollback(). In any
+                # case we want to have an informative exception raised.
+                try:
+                    transaction.commit()
+                except:
+                    # If the rollback fails, the transaction state will be
+                    # messed up. It doesn't matter, the connection will be set
+                    # to clean state after the request finishes. And, we can't
+                    # clean the state here properly even if we wanted to, the
+                    # connection is in transaction but we can't rollback...
+                    transaction.rollback()
+                    transaction.leave_transaction_management()
+                    raise
             transaction.leave_transaction_management()
         return response
diff --git a/tests/regressiontests/middleware/tests.py b/tests/regressiontests/middleware/tests.py
index a9a45c9..6c43641 100644
--- a/tests/regressiontests/middleware/tests.py
+++ b/tests/regressiontests/middleware/tests.py
@@ -9,9 +9,9 @@ import warnings
 
 from django.conf import settings
 from django.core import mail
-from django.db import transaction
-from django.http import HttpRequest
-from django.http import HttpResponse, StreamingHttpResponse
+from django.db import (transaction, connections, DEFAULT_DB_ALIAS,
+                       IntegrityError)
+from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
 from django.middleware.clickjacking import XFrameOptionsMiddleware
 from django.middleware.common import CommonMiddleware, BrokenLinkEmailsMiddleware
 from django.middleware.http import ConditionalGetMiddleware
@@ -710,3 +710,22 @@ class TransactionMiddlewareTest(TransactionTestCase):
         TransactionMiddleware().process_exception(self.request, None)
         self.assertEqual(Band.objects.count(), 0)
         self.assertFalse(transaction.is_dirty())
+
+    def test_failing_commit(self):
+        # It is possible that connection.commit() fails. Check that
+        # TransactionMiddleware handles such cases correctly.
+        try:
+            def raise_exception():
+                raise IntegrityError()
+            connections[DEFAULT_DB_ALIAS].commit = raise_exception
+            transaction.enter_transaction_management()
+            transaction.managed(True)
+            Band.objects.create(name='The Beatles')
+            self.assertTrue(transaction.is_dirty())
+            with self.assertRaises(IntegrityError):
+                TransactionMiddleware().process_response(self.request, None)
+            self.assertEqual(Band.objects.count(), 0)
+            self.assertFalse(transaction.is_dirty())
+            self.assertFalse(transaction.is_managed())
+        finally:
+            del connections[DEFAULT_DB_ALIAS].commit
diff --git a/tests/regressiontests/requests/tests.py b/tests/regressiontests/requests/tests.py
index 799cd9b..a29fb36 100644
--- a/tests/regressiontests/requests/tests.py
+++ b/tests/regressiontests/requests/tests.py
@@ -6,9 +6,12 @@ import warnings
 from datetime import datetime, timedelta
 from io import BytesIO
 
+from django.db import connection
+from django.core import signals
 from django.core.exceptions import SuspiciousOperation
 from django.core.handlers.wsgi import WSGIRequest, LimitedStream
 from django.http import HttpRequest, HttpResponse, parse_cookie, build_request_repr, UnreadablePostError
+from django.test import TransactionTestCase
 from django.test.client import FakePayload
 from django.test.utils import override_settings, str_prefix
 from django.utils import six
@@ -524,3 +527,21 @@ class RequestsTests(unittest.TestCase):
 
         with self.assertRaises(UnreadablePostError):
             request.body
+
+class TransactionRequestTests(TransactionTestCase):
+    # Need to run the test under real transaction handling.
+    def test_request_finished_db_state(self):
+        # The GET below will not succeed, but it will give a response with
+        # defined ._handler_class. That is needed for sending the request_finished
+        # signal. However, the test client itself will not send request_finished
+        # signals.
+        response = self.client.get('/')
+        # Taking a cursor will open a new connection.
+        connection.cursor()
+        connection.enter_transaction_management()
+        signals.request_finished.send(sender=response._handler_class)
+        # in-memory sqlite doesn't actually close connections when connections are closed.
+        if connection.vendor != 'sqlite':
+            self.assertIs(connection.connection, None)
+        # And the transaction state is reset.
+        self.assertEqual(len(connection.transaction_state), 0)
