diff --git includes/ajax.inc includes/ajax.inc
index 37b3d9c..426da70 100644
--- includes/ajax.inc
+++ includes/ajax.inc
@@ -29,7 +29,9 @@
  *   - A form element has a #ajax member.
  *   - On the specified element, AJAX processing is triggered by a change to
  *     that element.
- *   - The form is submitted and rebuilt.
+ *   - The form is submitted to the server and gets processed as usual by the
+ *     form API. If #ajax is in use, the form API automatically rebuilds the
+ *     form.
  *   - The function named by #ajax['callback'] is called, which returns content
  *     or an array of AJAX framework commands.
  *   - The content returned by the callback replaces the div on the page
diff --git includes/form.inc includes/form.inc
index 3f5cc99..a0e3e2e 100644
--- includes/form.inc
+++ includes/form.inc
@@ -219,11 +219,12 @@ function drupal_get_form($form_id) {
  *     request (so a browser refresh does not re-submit the form). However, if
  *     'rebuild' has been set to TRUE, then a new copy of the form is
  *     immediately built and sent to the browser; instead of a redirect. This is
- *     used for multi-step forms, such as wizards and confirmation forms. Also,
- *     if a form validation handler has set 'rebuild' to TRUE and a validation
- *     error occurred, then the form is rebuilt prior to being returned,
- *     enabling form elements to be altered, as appropriate to the particular
- *     validation error.
+ *     used for AJAX requests and multi-step forms, such as wizards and
+ *     confirmation forms.
+ *     Note that 'rebuild' is disabled by default, with the exception of the
+ *     triggering element making use of AJAX. Thus if the triggering element has
+ *     the #ajax property set, rebuilding is enabled automatically for both -
+ *     AJAX and non-AJAX form submits.
  *   - input: An array of input that corresponds to $_POST or $_GET, depending
  *     on the 'method' chosen (see below).
  *   - method: The HTTP form method to use for finding the input for this form.
@@ -233,6 +234,8 @@ function drupal_get_form($form_id) {
  *     forms that do not change data, as that is exclusively the domain of post.
  *   - no_redirect: If set to TRUE the form will NOT perform a drupal_goto(),
  *     even if 'redirect' is set.
+ *   - no_rebuild: If set to TRUE the form will NOT rebuild even if 'rebuild' is
+ *     set.
  *   - cache: If set to TRUE the original, unprocessed form structure will be
  *     cached, which allows to rebuild the entire form from cache.
  *   - no_cache: If set to TRUE the form will NOT be cached, even if 'cache' is
@@ -513,6 +516,7 @@ function form_state_keys_no_cache() {
     'must_validate',
     'rebuild',
     'rebuild_info',
+    'no_rebuild',
     'redirect',
     'no_redirect',
     'temporary',
@@ -806,11 +810,19 @@ function drupal_process_form($form_id, &$form, &$form_state) {
     }
   }
 
+  // If the triggering element makes use of AJAX, enable rebuilding by default.
+  // To ensure AJAX enabled buttons properly degrade when used without
+  // Javascript, we enable rebuilding regardless whether the form has just been
+  // submitted with AJAX or not.
+  if (!empty($form_state['triggering_element']['#ajax'])) {
+    $form_state['rebuild'] = TRUE;
+  }
+
   // If $form_state['rebuild'] has been set and input has been processed without
   // validation errors, we're in a multi-step workflow that is not yet complete.
   // We need to construct a new $form based on the changes made to $form_state
   // during this request.
-  if ($form_state['rebuild'] && $form_state['process_input'] && !form_get_errors()) {
+  if ($form_state['rebuild'] && empty($form_state['no_rebuild']) && $form_state['process_input'] && !form_get_errors()) {
     $form = drupal_rebuild_form($form_id, $form_state, $form);
   }
   // After processing the form, the form builder or a #process callback may
