Index: tests/phpunit/tests/option/registration.php
===================================================================
--- tests/phpunit/tests/option/registration.php	(revision 38908)
+++ tests/phpunit/tests/option/registration.php	(working copy)
@@ -40,6 +40,28 @@
 	}
 
 	/**
+	 * @ticket 38176
+	 */
+	public function test_register_with_default() {
+		register_setting( 'test_group', 'test_default', array(
+			'default' => 'Fuck Cancer'
+		));
+
+		$this->assertEquals( 'Fuck Cancer', get_option( 'test_default' ) );
+	}
+
+	/**
+	 * @ticket 38176
+	 */
+	public function test_register_with_default_override() {
+		register_setting( 'test_group', 'test_default', array(
+			'default' => 'Fuck Cancer'
+		));
+
+		$this->assertEquals( 'Fuck Leukemia', get_option( 'test_default', 'Fuck Leukemia' ) );
+	}
+
+	/**
 	 * @expectedDeprecated register_setting
 	 */
 	public function test_register_deprecated_group_misc() {
Index: src/wp-includes/option.php
===================================================================
--- src/wp-includes/option.php	(revision 38908)
+++ src/wp-includes/option.php	(working copy)
@@ -56,6 +56,9 @@
 	if ( defined( 'WP_SETUP_CONFIG' ) )
 		return false;
 
+	// Distinguish between `false` as a default, and not passing one.
+	$passed_default = func_num_args() > 1;
+
 	if ( ! wp_installing() ) {
 		// prevent non-existent options from triggering multiple queries
 		$notoptions = wp_cache_get( 'notoptions', 'options' );
@@ -67,12 +70,14 @@
 			 *
 			 * @since 3.4.0
 			 * @since 4.4.0 The `$option` parameter was added.
+			 * @since 4.7.0 The `$passed_default` parameter was added to distinguish between a `false` value and the default parameter value.
 			 *
 			 * @param mixed  $default The default value to return if the option does not exist
 			 *                        in the database.
 			 * @param string $option  Option name.
+			 * @param bool   $passed_default Was `get_option()` passed a default value?
 			 */
-			return apply_filters( "default_option_{$option}", $default, $option );
+			return apply_filters( "default_option_{$option}", $default, $option, $passed_default );
 		}
 
 		$alloptions = wp_load_alloptions();
@@ -97,7 +102,7 @@
 					wp_cache_set( 'notoptions', $notoptions, 'options' );
 
 					/** This filter is documented in wp-includes/option.php */
-					return apply_filters( 'default_option_' . $option, $default, $option );
+					return apply_filters( 'default_option_' . $option, $default, $option, $passed_default );
 				}
 			}
 		}
@@ -109,7 +114,7 @@
 			$value = $row->option_value;
 		} else {
 			/** This filter is documented in wp-includes/option.php */
-			return apply_filters( 'default_option_' . $option, $default, $option );
+			return apply_filters( 'default_option_' . $option, $default, $option, $passed_default );
 		}
 	}
 
@@ -1835,6 +1840,7 @@
  *     @type string   $description       A description of the data attached to this setting.
  *     @type callable $sanitize_callback A callback function that sanitizes the option's value.
  *     @type bool     $show_in_rest      Whether data associated with this setting should be included in the REST API.
+ *     @type mixed    $default           Default value when calling `get_option()`.
  * }
  */
 function register_setting( $option_group, $option_name, $args = array() ) {
@@ -1886,6 +1892,9 @@
 	if ( ! empty( $args['sanitize_callback'] ) ) {
 		add_filter( "sanitize_option_{$option_name}", $args['sanitize_callback'] );
 	}
+	if ( array_key_exists( 'default', $args ) ) {
+		add_filter( "default_option_{$option_name}", 'filter_default_option', 10, 3 );
+	}
 
 	$wp_registered_settings[ $option_name ] = $args;
 }
@@ -1950,3 +1959,29 @@
 
 	return $wp_registered_settings;
 }
+
+/**
+ * Filter the default value for the option.
+ *
+ * For settings which register a default setting in `register_setting()`, this
+ * function is added as a filter to `default_option_{$option}`.
+ *
+ * @since 4.7.0
+ *
+ * @param mixed $default Existing default value to return.
+ * @param string $option Option name.
+ * @param bool $passed_default Was `get_option()` passed a default value?
+ * @return mixed Filtered default value.
+ */
+function filter_default_option( $default, $option, $passed_default ) {
+	if ( $passed_default ) {
+		return $default;
+	}
+
+	$registered = get_registered_settings();
+	if ( empty( $registered[ $option ] ) ) {
+		return $default;
+	}
+
+	return $registered[ $option ]['default'];
+}
