diff -r d2539f0cf49c django/core/management/commands/syncdb.py
--- a/django/core/management/commands/syncdb.py	Mon Jan 17 14:03:19 2011 +0000
+++ b/django/core/management/commands/syncdb.py	Tue Jan 18 21:00:55 2011 +0800
@@ -26,6 +26,10 @@
         interactive = options.get('interactive')
         show_traceback = options.get('traceback', False)
 
+        # Stealth option -- 'load_initial_data' is used by the testing setup
+        # process to disable initial fixture loading.
+        load_initial_data = options.get('load_initial_data', True)
+
         self.style = no_style()
 
         # Import the 'management' module within each installed app, to register
@@ -154,5 +158,7 @@
                         else:
                             transaction.commit_unless_managed(using=db)
 
-        from django.core.management import call_command
-        call_command('loaddata', 'initial_data', verbosity=verbosity, database=db)
+        # Load initial_data fixtures (unless that has been disabled)
+        if load_initial_data:
+            from django.core.management import call_command
+            call_command('loaddata', 'initial_data', verbosity=verbosity, database=db)
diff -r d2539f0cf49c django/db/backends/creation.py
--- a/django/db/backends/creation.py	Mon Jan 17 14:03:19 2011 +0000
+++ b/django/db/backends/creation.py	Tue Jan 18 21:00:55 2011 +0800
@@ -359,7 +359,21 @@
         # 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)
-        call_command('syncdb', verbosity=max(verbosity - 1, 0), interactive=False, database=self.connection.alias)
+        call_command('syncdb',
+            verbosity=max(verbosity - 1, 0),
+            interactive=False,
+            database=self.connection.alias,
+            load_initial_data=False)
+
+        # We need to then do a flush to ensure that any data installed by
+        # custom SQL has been removed. The only test data should come from
+        # test fixtures, or autogenerated from post_syncdb triggers.
+        # This has the side effect of loading initial data (which was
+        # intentionally skipped in the syncdb).
+        call_command('flush',
+            verbosity=max(verbosity - 1, 0),
+            interactive=False,
+            database=self.connection.alias)
 
         from django.core.cache import get_cache
         from django.core.cache.backends.db import BaseDatabaseCache
diff -r d2539f0cf49c docs/howto/initial-data.txt
--- a/docs/howto/initial-data.txt	Mon Jan 17 14:03:19 2011 +0000
+++ b/docs/howto/initial-data.txt	Tue Jan 18 21:00:55 2011 +0800
@@ -121,6 +121,17 @@
 that, by the time your custom data files are executed, all the
 database tables already will have been created.
 
+.. admonition:: Initial SQL data and testing
+
+    This technique *cannot* be used to provide initial data for
+    testing purposes. Django's test framework flushes the contents of
+    the test database after each test; as a result, any data added
+    using the custom SQL hook will be lost.
+
+    If you require data for a test case, you should add it using
+    either a :ref:`test fixture <topics-testing-fixtures>`, or
+    programatically add it during the ``setUp()`` of your test case.
+
 Database-backend-specific SQL data
 ----------------------------------
 
diff -r d2539f0cf49c docs/topics/testing.txt
--- a/docs/topics/testing.txt	Mon Jan 17 14:03:19 2011 +0000
+++ b/docs/topics/testing.txt	Tue Jan 18 21:00:55 2011 +0800
@@ -1237,6 +1237,15 @@
     Fixtures with other names can always be installed manually using
     the :djadmin:`manage.py loaddata<loaddata>` command.
 
+.. admonition:: Initial SQL data and testing
+
+    Django provides a second way to insert initial data into models --
+    the :ref:`custom SQL hook <initial-sql>`. However, this technique
+    *cannot* be used to provide initial data for testing purposes.
+    Django's test framework flushes the contents of the test database
+    after each test; as a result, any data added using the custom SQL
+    hook will be lost.
+
 Once you've created a fixture and placed it in a ``fixtures`` directory in one
 of your :setting:`INSTALLED_APPS`, you can use it in your unit tests by
 specifying a ``fixtures`` class attribute on your :class:`django.test.TestCase`
diff -r d2539f0cf49c tests/regressiontests/initial_sql_regress/models.py
--- a/tests/regressiontests/initial_sql_regress/models.py	Mon Jan 17 14:03:19 2011 +0000
+++ b/tests/regressiontests/initial_sql_regress/models.py	Tue Jan 18 21:00:55 2011 +0800
@@ -7,5 +7,3 @@
 class Simple(models.Model):
     name = models.CharField(max_length = 50)
 
-# NOTE: The format of the included SQL file for this test suite is important.
-# It must end with a trailing newline in order to test the fix for #2161.
diff -r d2539f0cf49c tests/regressiontests/initial_sql_regress/tests.py
--- a/tests/regressiontests/initial_sql_regress/tests.py	Mon Jan 17 14:03:19 2011 +0000
+++ b/tests/regressiontests/initial_sql_regress/tests.py	Tue Jan 18 21:00:55 2011 +0800
@@ -5,4 +5,11 @@
 
 class InitialSQLTests(TestCase):
     def test_initial_sql(self):
-        self.assertEqual(Simple.objects.count(), 7)
+        # The format of the included SQL file for this test suite is important.
+        # It must end with a trailing newline in order to test the fix for #2161.
+
+        # However, as pointed out by #14661, test data loaded by custom SQL
+        # can't be relied upon; as a result, the test framework flushes the
+        # data contents before every test. This test validates that this has
+        # occurred.
+        self.assertEqual(Simple.objects.count(), 0)
