diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index dcd2f01..0c53006 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -16,6 +16,7 @@ __all__ = ('BaseFormSet', 'all_valid')
 TOTAL_FORM_COUNT = 'TOTAL_FORMS'
 INITIAL_FORM_COUNT = 'INITIAL_FORMS'
 MAX_NUM_FORM_COUNT = 'MAX_NUM_FORMS'
+MIN_NUM_FORM_COUNT = 'MIN_NUM_FORMS'
 ORDERING_FIELD_NAME = 'ORDER'
 DELETION_FIELD_NAME = 'DELETE'
 
@@ -29,6 +30,7 @@ class ManagementForm(Form):
         self.base_fields[TOTAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
         self.base_fields[INITIAL_FORM_COUNT] = IntegerField(widget=HiddenInput)
         self.base_fields[MAX_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput)
+        self.base_fields[MIN_NUM_FORM_COUNT] = IntegerField(required=False, widget=HiddenInput)
         super(ManagementForm, self).__init__(*args, **kwargs)
 
 class BaseFormSet(StrAndUnicode):
@@ -77,7 +79,8 @@ class BaseFormSet(StrAndUnicode):
             form = ManagementForm(auto_id=self.auto_id, prefix=self.prefix, initial={
                 TOTAL_FORM_COUNT: self.total_form_count(),
                 INITIAL_FORM_COUNT: self.initial_form_count(),
-                MAX_NUM_FORM_COUNT: self.max_num
+                MAX_NUM_FORM_COUNT: self.max_num,
+                MIN_NUM_FORM_COUNT: self.min_num
             })
         return form
     management_form = property(_management_form)
@@ -95,6 +98,9 @@ class BaseFormSet(StrAndUnicode):
                 total_forms = initial_forms
             elif total_forms > self.max_num >= 0:
                 total_forms = self.max_num
+
+            total_forms = max(total_forms, self.min_num)
+
         return total_forms
 
     def initial_form_count(self):
@@ -358,13 +364,17 @@ class BaseFormSet(StrAndUnicode):
         return mark_safe(u'\n'.join([unicode(self.management_form), forms]))
 
 def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False,
-                    can_delete=False, max_num=None):
+                    can_delete=False, max_num=None, min_num=None):
     """Return a FormSet for the given form class."""
+    if not None in (max_num, min_num) and max_num < min_num:
+        raise ValueError('max_num cannot be smaller than min_num')
+
     attrs = {'form': form, 'extra': extra,
              'can_order': can_order, 'can_delete': can_delete,
-             'max_num': max_num}
+             'max_num': max_num, 'min_num': min_num }
     return type(form.__name__ + 'FormSet', (formset,), attrs)
 
+
 def all_valid(formsets):
     """Returns true if every formset in formsets is valid."""
     valid = True
diff --git a/docs/topics/forms/formsets.txt b/docs/topics/forms/formsets.txt
index b524c24..9a91182 100644
--- a/docs/topics/forms/formsets.txt
+++ b/docs/topics/forms/formsets.txt
@@ -112,6 +112,36 @@ A ``max_num`` value of ``None`` (the default) puts no limit on the number of
 forms displayed. Please note that the default value of ``max_num`` was changed
 from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value.
 
+.. _formsets-min-num:
+
+Ensuring the minimum number of forms
+------------------------------------
+
+The ``min_num`` parameter to ``formset_factory`` gives you the ability to make
+sure that at least a certain number of forms will be displayed::
+
+    >>> ArticleFormSet = formset_factory(ArticleForm, min_num=2)
+    >>> formset = ArticleFormset(initial=[
+    ...     {'title': u'Django is now open source',
+    ...      'pub_date': datetime.date.today(),}
+    ... ])
+
+    >>> for form in formset:
+    ...     print form.as_table()
+    <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
+    <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2012-04-02" id="id_form-0-pub_date" /></td></tr>
+    <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
+    <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
+
+.. versionchanged:: 1.4
+
+If the value of ``min_num`` is greater than the number of elements that would
+be displayed normally (including extra forms), additional blank forms will be
+added to the formset.
+
+If ``min_num`` is greater than ``max_num``, ``ValueError`` will be raised by
+``formset_factory`` function.
+
 Formset validation
 ------------------
 
diff --git a/tests/regressiontests/forms/tests/formsets.py b/tests/regressiontests/forms/tests/formsets.py
index 05ef978..957f04b 100644
--- a/tests/regressiontests/forms/tests/formsets.py
+++ b/tests/regressiontests/forms/tests/formsets.py
@@ -47,7 +47,7 @@ class FormsFormsetTestCase(TestCase):
         # for adding data. By default, it displays 1 blank form. It can display more,
         # but we'll look at how to do so later.
         formset = ChoiceFormSet(auto_id=False, prefix='choices')
-        self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" />
+        self.assertHTMLEqual(str(formset), """<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" /><input type="hidden" name="choices-MIN_NUM_FORMS" />
 <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr>
 <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr>""")
 
@@ -646,6 +646,52 @@ class FormsFormsetTestCase(TestCase):
         self.assertTrue(formset.is_valid())
         self.assertEqual(formset.non_form_errors(), [])
 
+    def test_appending_min_forms(self):
+        # Ensuring the minimum number of forms ########################################
+        # Base case for min_num.
+
+        # When not passed, min_num will take its default value of None, i.e. no required
+        # forms, only controller by the value of the extra parameter.
+
+        initial = [ dict(name='Pony') ]
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=0, min_num=1)
+        formset = LimitedFavoriteDrinkFormSet()
+
+        self.assertHTMLEqual('\n'.join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>""")
+
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=0, min_num=2)
+        formset = LimitedFavoriteDrinkFormSet(initial=initial)
+
+        self.assertHTMLEqual('\n'.join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" value="Pony" /></td></tr>
+<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>""")
+
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=0, min_num=1)
+        formset = LimitedFavoriteDrinkFormSet(initial=initial)
+
+        self.assertHTMLEqual('\n'.join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" value="Pony" /></td></tr>""")
+
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, min_num=1)
+        formset = LimitedFavoriteDrinkFormSet(initial=initial)
+
+        self.assertHTMLEqual('\n'.join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" value="Pony" /></td></tr>
+<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr>""")
+
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, min_num=1, max_num=1)
+        formset = LimitedFavoriteDrinkFormSet(initial=initial)
+
+        self.assertHTMLEqual('\n'.join(str(form) for form in formset.forms), """<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" value="Pony" /></td></tr>""")
+
+    def test_formset_management_form_contains_min_num(self):
+        self.maxDiff = None
+        LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=0, min_num=1)
+        formset = LimitedFavoriteDrinkFormSet()
+
+        self.assertHTMLEqual(str(formset), """<input type="hidden" id="id_form-TOTAL_FORMS" name="form-TOTAL_FORMS" value="1" /><input type="hidden" id="id_form-INITIAL_FORMS" name="form-INITIAL_FORMS" value="0" /><input type="hidden" id="id_form-MAX_NUM_FORMS" name="form-MAX_NUM_FORMS" /><input type="hidden" id="id_form-MIN_NUM_FORMS" name="form-MIN_NUM_FORMS" value="1" />
+<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr>""")
+
+    def test_wrong_min_forms(self):
+        self.assertRaises(ValueError, formset_factory, FavoriteDrinkForm, min_num=2, max_num=1)
+
     def test_limiting_max_forms(self):
         # Limiting the maximum number of forms ########################################
         # Base case for max_num.
@@ -862,19 +908,19 @@ ChoiceFormSet = formset_factory(Choice)
 class FormsetAsFooTests(TestCase):
     def test_as_table(self):
         formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
-        self.assertHTMLEqual(formset.as_table(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
+        self.assertHTMLEqual(formset.as_table(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" />
 <tr><th>Choice:</th><td><input type="text" name="choices-0-choice" value="Calexico" /></td></tr>
 <tr><th>Votes:</th><td><input type="text" name="choices-0-votes" value="100" /></td></tr>""")
 
     def test_as_p(self):
         formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
-        self.assertHTMLEqual(formset.as_p(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
+        self.assertHTMLEqual(formset.as_p(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" />
 <p>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></p>
 <p>Votes: <input type="text" name="choices-0-votes" value="100" /></p>""")
 
     def test_as_ul(self):
         formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
-        self.assertHTMLEqual(formset.as_ul(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" />
+        self.assertHTMLEqual(formset.as_ul(),"""<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /><input type="hidden" name="choices-MAX_NUM_FORMS" value="0" /><input type="hidden" name="choices-MIN_NUM_FORMS" />
 <li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li>
 <li>Votes: <input type="text" name="choices-0-votes" value="100" /></li>""")
 
