diff --git a/TODO b/TODO
index f52e6e736b51f2324f548570a4509f874929f520..38545e0bc304f62e5fbcd5332327f1239e44fb69 100644
--- a/TODO
+++ b/TODO
@@ -25,8 +25,6 @@ Ideas
 
 - Change "end session" link for sessions that don't actually end.
 
-- Session reset UI
-
 - Manual grade entry/override
 
 - Flow results analytics
diff --git a/course/content.py b/course/content.py
index bc0f6d7cd7920ea9b70b26cf7c21cdea6471b44f..84f71549b39beafae89e963a9a59fcbd50887e38 100644
--- a/course/content.py
+++ b/course/content.py
@@ -32,6 +32,7 @@ import six
 
 from django.utils.timezone import now
 from django.core.exceptions import ObjectDoesNotExist, ImproperlyConfigured
+from django.db import transaction
 
 from markdown.extensions import Extension
 from markdown.treeprocessors import Treeprocessor
@@ -725,33 +726,53 @@ def instantiate_flow_page(location, repo, page_desc, commit_sha):
     return class_(None, location, page_desc)
 
 
-def set_up_flow_session_page_data(repo, flow_session,
+@transaction.atomic
+def adjust_flow_session_page_data(repo, flow_session,
         course_identifier, flow_desc, commit_sha):
     from course.models import FlowPageData
 
+    id_to_existing_page = {
+            (data.group_id, data.page_id): data
+            for data in FlowPageData.objects.filter(flow_session=flow_session)
+            }
+
     data = None
 
     ordinal = 0
     for grp in flow_desc.groups:
         for page_desc in grp.pages:
-            data = FlowPageData()
-            data.flow_session = flow_session
-            data.ordinal = ordinal
-            data.is_last = False
-            data.group_id = grp.id
-            data.page_id = page_desc.id
-
-            page = instantiate_flow_page(
-                    "course '%s', flow '%s', page '%s/%s'"
-                    % (course_identifier, flow_session.flow_id,
-                        grp.id, page_desc.id),
-                    repo, page_desc, commit_sha)
-            data.data = page.make_page_data()
-            data.save()
+            key = (grp.id, page_desc.id)
+
+            if key in id_to_existing_page:
+                data = id_to_existing_page.pop(key)
+                if data.ordinal != ordinal:
+                    data.ordinal = ordinal
+                    data.save()
+            else:
+                data = FlowPageData()
+                data.flow_session = flow_session
+                data.ordinal = ordinal
+                data.group_id = grp.id
+                data.page_id = page_desc.id
+
+                page = instantiate_flow_page(
+                        "course '%s', flow '%s', page '%s/%s'"
+                        % (course_identifier, flow_session.flow_id,
+                            grp.id, page_desc.id),
+                        repo, page_desc, commit_sha)
+                data.data = page.make_page_data()
+                data.save()
 
             ordinal += 1
 
-    return ordinal
+    for data in id_to_existing_page.values():
+        if data.ordinal is not None:
+            data.ordinal = None
+            data.save()
+
+    if flow_session.page_count != ordinal:
+        flow_session.page_count = ordinal
+        flow_session.save()
 
 
 def get_course_commit_sha(course, participation):
diff --git a/course/flow.py b/course/flow.py
index 3c8eb7655bac40e3658cb6461b49eae64d272cbc..bd6f6410350946b6f2897ad35fa9c8df3359a5a3 100644
--- a/course/flow.py
+++ b/course/flow.py
@@ -704,7 +704,7 @@ def start_flow(pctx, flow_identifier):
             pctx.role, flow_identifier, fctx.flow_desc, now_datetime)
 
     if request.method == "POST":
-        from course.content import set_up_flow_session_page_data
+        from course.content import adjust_flow_session_page_data
 
         if "start" in request.POST:
 
@@ -740,10 +740,9 @@ def start_flow(pctx, flow_identifier):
                                     grading_rule, "grade_aggregation_strategy"),
                                 ))
 
-            page_count = set_up_flow_session_page_data(fctx.repo, session,
+            # will implicitly modify and save the session if there are changes
+            adjust_flow_session_page_data(fctx.repo, session,
                     pctx.course.identifier, fctx.flow_desc, pctx.course_commit_sha)
-            session.page_count = page_count
-            session.save()
 
             return redirect("course.flow.view_flow_page",
                     pctx.course.identifier, session.id, 0)
diff --git a/course/migrations/0046_allow_null_page_data_ordinals.py b/course/migrations/0046_allow_null_page_data_ordinals.py
new file mode 100644
index 0000000000000000000000000000000000000000..cacb35fbe230e27c33eab881ed3063fc903a4730
--- /dev/null
+++ b/course/migrations/0046_allow_null_page_data_ordinals.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('course', '0045_add_course_listed'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='flowpagedata',
+            name='ordinal',
+            field=models.IntegerField(null=True, blank=True),
+            preserve_default=True,
+        ),
+    ]
diff --git a/course/migrations/0047_remove_page_data_ordinal_uniqueness.py b/course/migrations/0047_remove_page_data_ordinal_uniqueness.py
new file mode 100644
index 0000000000000000000000000000000000000000..3c066c10ae8d2768bd55dcfd9f3a73fe3ca34e1b
--- /dev/null
+++ b/course/migrations/0047_remove_page_data_ordinal_uniqueness.py
@@ -0,0 +1,18 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('course', '0046_allow_null_page_data_ordinals'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='flowpagedata',
+            unique_together=set([]),
+        ),
+    ]
diff --git a/course/models.py b/course/models.py
index 5fbec6a083c3b7e0c3cd3d5c3b59d0de902f9aa7..94e4c7fab1b09009bc191b31a6e33d45be270960 100644
--- a/course/models.py
+++ b/course/models.py
@@ -340,7 +340,7 @@ class FlowSession(models.Model):
 
 class FlowPageData(models.Model):
     flow_session = models.ForeignKey(FlowSession, related_name="page_data")
-    ordinal = models.IntegerField()
+    ordinal = models.IntegerField(null=True, blank=True)
 
     group_id = models.CharField(max_length=200)
     page_id = models.CharField(max_length=200)
@@ -348,7 +348,6 @@ class FlowPageData(models.Model):
     data = JSONField(null=True, blank=True)
 
     class Meta:
-        unique_together = (("flow_session", "ordinal"),)
         verbose_name_plural = "flow page data"
 
     def __unicode__(self):
diff --git a/course/utils.py b/course/utils.py
index 5d799ee02c73a945b2fee314efb32e1ee58d34c4..9129985e09b610c3158a8c8306605e8e35230947 100644
--- a/course/utils.py
+++ b/course/utils.py
@@ -305,6 +305,10 @@ class FlowPageContext(FlowContext):
         FlowContext.__init__(self, repo, course, flow_identifier,
                 participation, flow_session=flow_session)
 
+        from course.content import adjust_flow_session_page_data
+        adjust_flow_session_page_data(repo, flow_session,
+                course.identifier, self.flow_desc, self.course_commit_sha)
+
         from course.models import FlowPageData
         page_data = self.page_data = get_object_or_404(
                 FlowPageData, flow_session=flow_session, ordinal=ordinal)