diff --git a/django/db/migrations/migration.py b/django/db/migrations/migration.py
index ccbd2f72e4..ea9d02a94a 100644
--- a/django/db/migrations/migration.py
+++ b/django/db/migrations/migration.py
@@ -103,15 +103,14 @@ class Migration:
             # there instead
             if collect_sql:
                 schema_editor.collected_sql.append("--")
-                if not operation.reduces_to_sql:
-                    schema_editor.collected_sql.append(
-                        "-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS "
-                        "SQL:"
-                    )
                 schema_editor.collected_sql.append("-- %s" % operation.describe())
                 schema_editor.collected_sql.append("--")
                 if not operation.reduces_to_sql:
+                    schema_editor.collected_sql.append(
+                        "-- THIS OPERATION CANNOT BE WRITTEN AS SQL"
+                    )
                     continue
+                collected_sql_before = len(schema_editor.collected_sql)
             # Save the state before the operation has run
             old_state = project_state.clone()
             operation.state_forwards(self.app_label, project_state)
@@ -131,6 +130,8 @@ class Migration:
                 operation.database_forwards(
                     self.app_label, schema_editor, old_state, project_state
                 )
+            if collect_sql and collected_sql_before == len(schema_editor.collected_sql):
+                schema_editor.collected_sql.append("-- (no-op)")
         return project_state
 
     def unapply(self, project_state, schema_editor, collect_sql=False):
@@ -167,15 +168,14 @@ class Migration:
         for operation, to_state, from_state in to_run:
             if collect_sql:
                 schema_editor.collected_sql.append("--")
-                if not operation.reduces_to_sql:
-                    schema_editor.collected_sql.append(
-                        "-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE WRITTEN AS "
-                        "SQL:"
-                    )
                 schema_editor.collected_sql.append("-- %s" % operation.describe())
                 schema_editor.collected_sql.append("--")
                 if not operation.reduces_to_sql:
+                    schema_editor.collected_sql.append(
+                        "-- THIS OPERATION CANNOT BE WRITTEN AS SQL"
+                    )
                     continue
+                collected_sql_before = len(schema_editor.collected_sql)
             atomic_operation = operation.atomic or (
                 self.atomic and operation.atomic is not False
             )
@@ -191,6 +191,8 @@ class Migration:
                 operation.database_backwards(
                     self.app_label, schema_editor, from_state, to_state
                 )
+            if collect_sql and collected_sql_before == len(schema_editor.collected_sql):
+                schema_editor.collected_sql.append("-- (no-op)")
         return project_state
 
     def suggest_name(self):
diff --git a/tests/migrations/test_commands.py b/tests/migrations/test_commands.py
index 7ea8267247..a3e1efc924 100644
--- a/tests/migrations/test_commands.py
+++ b/tests/migrations/test_commands.py
@@ -1021,11 +1021,51 @@ class MigrateTests(MigrationTestBase):
     @override_settings(
         MIGRATION_MODULES={"migrations": "migrations.test_migrations_no_operations"}
     )
-    def test_migrations_no_operations(self):
+    def test_sqlmigrate_no_operations(self):
         err = io.StringIO()
         call_command("sqlmigrate", "migrations", "0001_initial", stderr=err)
         self.assertEqual(err.getvalue(), "No operations found.\n")
 
+    @override_settings(
+        MIGRATION_MODULES={"migrations": "migrations.test_migrations_noop"}
+    )
+    def test_sqlmigrate_noop(self):
+        out = io.StringIO()
+        call_command("sqlmigrate", "migrations", "0001", stdout=out)
+        lines = out.getvalue().splitlines()
+
+        if connection.features.can_rollback_ddl:
+            lines = lines[1:-1]
+        self.assertEqual(
+            lines,
+            [
+                "--",
+                "-- Raw SQL operation",
+                "--",
+                "-- (no-op)",
+            ],
+        )
+
+    @override_settings(
+        MIGRATION_MODULES={"migrations": "migrations.test_migrations_manual_porting"}
+    )
+    def test_sqlmigrate_unrepresentable(self):
+        out = io.StringIO()
+        call_command("sqlmigrate", "migrations", "0002", stdout=out)
+        lines = out.getvalue().splitlines()
+
+        if connection.features.can_rollback_ddl:
+            lines = lines[1:-1]
+        self.assertEqual(
+            lines,
+            [
+                "--",
+                "-- Raw Python operation",
+                "--",
+                "-- THIS OPERATION CANNOT BE WRITTEN AS SQL",
+            ],
+        )
+
     @override_settings(
         INSTALLED_APPS=[
             "migrations.migrations_test_apps.migrated_app",
diff --git a/tests/migrations/test_migrations_noop/0001_initial.py b/tests/migrations/test_migrations_noop/0001_initial.py
new file mode 100644
index 0000000000..f06ff893ad
--- /dev/null
+++ b/tests/migrations/test_migrations_noop/0001_initial.py
@@ -0,0 +1,10 @@
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    operations = [
+        migrations.RunSQL(sql="", reverse_sql=""),
+    ]
diff --git a/tests/migrations/test_migrations_noop/__init__.py b/tests/migrations/test_migrations_noop/__init__.py
new file mode 100644
index 0000000000..e69de29bb2