diff --git a/django/core/management/commands/migrate.py b/django/core/management/commands/migrate.py
index 191bc2c39d..3e796b655f 100644
--- a/django/core/management/commands/migrate.py
+++ b/django/core/management/commands/migrate.py
@@ -14,6 +14,9 @@ from django.core.management.sql import custom_sql_for_model, emit_post_migrate_s
 from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
 from django.db.migrations.executor import MigrationExecutor
 from django.db.migrations.loader import MigrationLoader, AmbiguityError
+from django.db.migrations.state import ProjectState
+from django.db.migrations.autodetector import MigrationAutodetector
+from django.db.models.loading import cache
 from django.utils.module_loading import module_has_submodule
 
 
@@ -120,6 +123,15 @@ class Command(BaseCommand):
         if not plan:
             if self.verbosity >= 1:
                 self.stdout.write("  No migrations needed.")
+                # If there's changes that aren't in migrations yet, tell them how to fix it.
+                autodetector = MigrationAutodetector(
+                    executor.loader.graph.project_state(),
+                    ProjectState.from_app_cache(cache),
+                )
+                changes = autodetector.changes(graph=executor.loader.graph)
+                if changes:
+                    self.stdout.write(self.style.NOTICE("  Your models have changes that are not yet reflected in a migration, and so won't be applied."))
+                    self.stdout.write(self.style.NOTICE("  Run 'manage.py makemigrations' to make new migrations, and then re-run 'manage.py migrate' to apply them."))
         else:
             executor.migrate(targets, plan, fake=options.get("fake", False))
 
diff --git a/django/core/management/commands/runserver.py b/django/core/management/commands/runserver.py
index 503cff220f..327832ba43 100644
--- a/django/core/management/commands/runserver.py
+++ b/django/core/management/commands/runserver.py
@@ -10,6 +10,8 @@ import socket
 
 from django.core.management.base import BaseCommand, CommandError
 from django.core.servers.basehttp import run, get_internal_wsgi_application
+from django.db import connections, DEFAULT_DB_ALIAS
+from django.db.migrations.executor import MigrationExecutor
 from django.utils import autoreload
 from django.utils import six
 
@@ -99,10 +101,10 @@ class Command(BaseCommand):
 
         self.stdout.write("Validating models...\n\n")
         self.validate(display_num_errors=True)
+        self.check_migrations()
         now = datetime.now().strftime('%B %d, %Y - %X')
         if six.PY2:
             now = now.decode('utf-8')
-
         self.stdout.write((
             "%(started_at)s\n"
             "Django version %(version)s, using settings %(settings)r\n"
@@ -144,6 +146,16 @@ class Command(BaseCommand):
                 self.stdout.write(shutdown_message)
             sys.exit(0)
 
+    def check_migrations(self):
+        """
+        Checks to see if the set of migrations on disk matches the
+        migrations in the database. Prints a warning if they don't match.
+        """
+        executor = MigrationExecutor(connections[DEFAULT_DB_ALIAS])
+        plan = executor.migration_plan(executor.loader.graph.leaf_nodes())
+        if plan:
+            self.stdout.write(self.style.NOTICE("\nYou have unapplied migrations; your app may not work properly until they are applied."))
+            self.stdout.write(self.style.NOTICE("Run 'python manage.py migrate' to apply them.\n"))
 
 # Kept for backward compatibility
 BaseRunserverCommand = Command