Index: src/wp-admin/includes/template-functions.php
===================================================================
--- src/wp-admin/includes/template-functions.php	(revision 35406)
+++ src/wp-admin/includes/template-functions.php	(working copy)
@@ -585,13 +585,42 @@
 	 * @param int $limit Number of custom fields to retrieve. Default 30.
 	 */
 	$limit = apply_filters( 'postmeta_form_limit', 30 );
-	$sql = "SELECT DISTINCT meta_key
-		FROM $wpdb->postmeta
-		WHERE meta_key NOT BETWEEN '_' AND '_z'
-		HAVING meta_key NOT LIKE %s
-		ORDER BY meta_key
-		LIMIT %d";
-	$keys = $wpdb->get_col( $wpdb->prepare( $sql, $wpdb->esc_like( '_' ) . '%', $limit ) );
+
+	/**
+	 * Filter the number of rows to retrieve from the database when searching
+	 * for custom field names.
+	 *
+	 * @since 4.4.0
+	 *
+	 * @param int $limit Number of rows to retrieve. Default 1000.
+	 */
+	$row_limit = apply_filters( 'postmeta_form_row_limit', 1000 );
+
+	$keys = array();
+	$offset = 0;
+	while( count( $keys ) < $limit ) {
+		$sql = "SELECT DISTINCT meta_key
+			FROM $wpdb->postmeta
+			LIMIT %d,%d";
+		$maybe_keys = $wpdb->get_col( $wpdb->prepare( $sql, $offset, $row_limit ) );
+
+		foreach ( $maybe_keys as $key ) {
+			if ( 0 !== strpos( $key, '_' ) ) {
+				$keys[] = $key;
+			}
+
+			if ( count( $keys ) >= $limit ) {
+				break 2;
+			}
+		}
+
+		if ( count( $maybe_keys ) < $row_limit ) {
+			break;
+		}
+
+		$offset += $row_limit;
+	}
+
 	if ( $keys ) {
 		natcasesort( $keys );
 		$meta_key_input_id = 'metakeyselect';
