diff -r e6ff4cef36b7 django/contrib/gis/db/backends/spatialite/creation.py
--- a/django/contrib/gis/db/backends/spatialite/creation.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/django/contrib/gis/db/backends/spatialite/creation.py	Tue Mar 13 19:52:05 2012 -0300
@@ -31,9 +31,6 @@
         self.connection.close()
         self.connection.settings_dict["NAME"] = test_database_name
 
-        # Confirm the feature set of the test database
-        self.connection.features.confirm()
-
         # Need to load the SpatiaLite initialization SQL before running `syncdb`.
         self.load_spatialite_sql()
 
diff -r e6ff4cef36b7 django/db/backends/__init__.py
--- a/django/db/backends/__init__.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/django/db/backends/__init__.py	Tue Mar 13 19:52:05 2012 -0300
@@ -10,6 +10,7 @@
 from django.db import DEFAULT_DB_ALIAS
 from django.db.backends import util
 from django.db.transaction import TransactionManagementError
+from django.utils.functional import cached_property
 from django.utils.importlib import import_module
 from django.utils.timezone import is_aware
 
@@ -399,12 +400,10 @@
     # in the SQL standard.
     supports_tablespaces = False
 
-    # Features that need to be confirmed at runtime
-    # Cache whether the confirmation has been performed.
-    _confirmed = False
-    supports_transactions = None
-    supports_stddev = None
-    can_introspect_foreign_keys = None
+    # Confirm support for introspected foreign keys
+    # Every database can do this reliably, except MySQL,
+    # which can't do it for MyISAM tables
+    can_introspect_foreign_keys = True
 
     # Support for the DISTINCT ON clause
     can_distinct_on_fields = False
@@ -412,14 +411,8 @@
     def __init__(self, connection):
         self.connection = connection
 
-    def confirm(self):
-        "Perform manual checks of any database features that might vary between installs"
-        self._confirmed = True
-        self.supports_transactions = self._supports_transactions()
-        self.supports_stddev = self._supports_stddev()
-        self.can_introspect_foreign_keys = self._can_introspect_foreign_keys()
-
-    def _supports_transactions(self):
+    @cached_property
+    def supports_transactions(self):
         "Confirm support for transactions"
         cursor = self.connection.cursor()
         cursor.execute('CREATE TABLE ROLLBACK_TEST (X INT)')
@@ -432,7 +425,8 @@
         self.connection._commit()
         return count == 0
 
-    def _supports_stddev(self):
+    @cached_property
+    def supports_stddev(self):
         "Confirm support for STDDEV and related stats functions"
         class StdDevPop(object):
             sql_function = 'STDDEV_POP'
@@ -440,12 +434,7 @@
         try:
             self.connection.ops.check_aggregate_support(StdDevPop())
         except NotImplementedError:
-            self.supports_stddev = False
-
-    def _can_introspect_foreign_keys(self):
-        "Confirm support for introspected foreign keys"
-        # Every database can do this reliably, except MySQL,
-        # which can't do it for MyISAM tables
+            return False
         return True
 
 
diff -r e6ff4cef36b7 django/db/backends/creation.py
--- a/django/db/backends/creation.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/django/db/backends/creation.py	Tue Mar 13 19:52:05 2012 -0300
@@ -258,9 +258,6 @@
         self.connection.close()
         self.connection.settings_dict["NAME"] = test_database_name
 
-        # Confirm the feature set of the test database
-        self.connection.features.confirm()
-
         # Report syncdb messages at one level lower than that requested.
         # This ensures we don't get flooded with messages during testing
         # (unless you really ask to be flooded)
diff -r e6ff4cef36b7 django/db/backends/mysql/base.py
--- a/django/db/backends/mysql/base.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/django/db/backends/mysql/base.py	Tue Mar 13 19:52:05 2012 -0300
@@ -33,6 +33,7 @@
 from django.db.backends.mysql.creation import DatabaseCreation
 from django.db.backends.mysql.introspection import DatabaseIntrospection
 from django.db.backends.mysql.validation import DatabaseValidation
+from django.utils.functional import cached_property
 from django.utils.safestring import SafeString, SafeUnicode
 from django.utils import timezone
 
@@ -166,26 +167,25 @@
 
     def __init__(self, connection):
         super(DatabaseFeatures, self).__init__(connection)
-        self._storage_engine = None
 
+    @cached_property
     def _mysql_storage_engine(self):
         "Internal method used in Django tests. Don't rely on this from your code"
-        if self._storage_engine is None:
-            cursor = self.connection.cursor()
-            cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
-            # This command is MySQL specific; the second column
-            # will tell you the default table type of the created
-            # table. Since all Django's test tables will have the same
-            # table type, that's enough to evaluate the feature.
-            cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
-            result = cursor.fetchone()
-            cursor.execute('DROP TABLE INTROSPECT_TEST')
-            self._storage_engine = result[1]
-        return self._storage_engine
+        cursor = self.connection.cursor()
+        cursor.execute('CREATE TABLE INTROSPECT_TEST (X INT)')
+        # This command is MySQL specific; the second column
+        # will tell you the default table type of the created
+        # table. Since all Django's test tables will have the same
+        # table type, that's enough to evaluate the feature.
+        cursor.execute("SHOW TABLE STATUS WHERE Name='INTROSPECT_TEST'")
+        result = cursor.fetchone()
+        cursor.execute('DROP TABLE INTROSPECT_TEST')
+        return result[1]
 
-    def _can_introspect_foreign_keys(self):
+    @cached_property
+    def can_introspect_foreign_keys(self):
         "Confirm support for introspected foreign keys"
-        return self._mysql_storage_engine() != 'MyISAM'
+        return self._mysql_storage_engine != 'MyISAM'
 
 class DatabaseOperations(BaseDatabaseOperations):
     compiler_module = "django.db.backends.mysql.compiler"
diff -r e6ff4cef36b7 django/db/backends/sqlite3/base.py
--- a/django/db/backends/sqlite3/base.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/django/db/backends/sqlite3/base.py	Tue Mar 13 19:52:05 2012 -0300
@@ -18,6 +18,7 @@
 from django.db.backends.sqlite3.creation import DatabaseCreation
 from django.db.backends.sqlite3.introspection import DatabaseIntrospection
 from django.utils.dateparse import parse_date, parse_datetime, parse_time
+from django.utils.functional import cached_property
 from django.utils.safestring import SafeString
 from django.utils import timezone
 
@@ -85,7 +86,8 @@
     has_bulk_insert = True
     can_combine_inserts_with_and_without_auto_increment_pk = True
 
-    def _supports_stddev(self):
+    @cached_property
+    def supports_stddev(self):
         """Confirm support for STDDEV and related stats functions
 
         SQLite supports STDDEV as an extension package; so
diff -r e6ff4cef36b7 tests/regressiontests/transactions_regress/tests.py
--- a/tests/regressiontests/transactions_regress/tests.py	Tue Mar 13 22:21:38 2012 +0000
+++ b/tests/regressiontests/transactions_regress/tests.py	Tue Mar 13 19:52:05 2012 -0300
@@ -208,7 +208,7 @@
         work()
 
     @skipIf(connection.vendor == 'mysql' and \
-            connection.features._mysql_storage_engine() == 'MyISAM',
+            connection.features._mysql_storage_engine == 'MyISAM',
             "MyISAM MySQL storage engine doesn't support savepoints")
     @skipUnlessDBFeature('uses_savepoints')
     def test_savepoint_rollback(self):
