Index: wp-admin/includes/template.php
===================================================================
--- wp-admin/includes/template.php	(revision 8072)
+++ wp-admin/includes/template.php	(working copy)
@@ -4,35 +4,70 @@
 // Big Mess
 //
 
-// Dandy new recursive multiple category stuff.
-function cat_rows( $parent = 0, $level = 0, $categories = 0 ) {
-	if ( !$categories ) {
+// Ugly recursive category stuff.
+function cat_rows( $parent = 0, $level = 0, &$categories = 0, $page = 1, $per_page = 20, &$count = 0 ) {
+	if ( empty($categories) ) {
 		$args = array('hide_empty' => 0);
-		if ( !empty($_GET['s']) )
+		if ( !empty($_GET['s']) ) {
 			$args['search'] = $_GET['s'];
+			$parent = -1;
+		}
 		$categories = get_categories( $args );
 	}
 
+	if ( !$categories )
+		return false;
+
 	$children = _get_term_hierarchy('category');
 
-	if ( $categories ) {
-		ob_start();
-		foreach ( $categories as $category ) {
-			if ( $category->parent == $parent) {
-				echo "\t" . _cat_row( $category, $level );
-				if ( isset($children[$category->term_id]) )
-					cat_rows( $category->term_id, $level +1, $categories );
+	$start = ($page - 1) * $per_page;
+	$end = $start + $per_page;
+	$i = -1;
+	ob_start();
+	foreach ( $categories as $category ) {
+		if ( $count >= $end )
+			break;
+
+		$i++;
+
+		if ( ($category->parent != $parent) && ( -1 != $parent) )
+			continue;
+
+		// If the page starts in a subtree, print the parents.
+		if ( $count == $start && $category->parent > 0 ) {
+			$my_parents = array();
+			$my_parent = $category->parent;
+			while ( $my_parent) {
+				$my_parent = get_category($my_parent);
+				$my_parents[] = $my_parent;
+				if ( !$my_parent->parent )
+					break;
+				$my_parent = $my_parent->parent;
 			}
+			$num_parents = count($my_parents);
+			while( $my_parent = array_pop($my_parents) ) {
+				echo "\t" . _cat_row( $my_parent, $level - $num_parents );
+				$num_parents--;
+			}
 		}
-		$output = ob_get_contents();
-		ob_end_clean();
 
-		$output = apply_filters('cat_rows', $output);
+		if ( $count >= $start )
+			echo "\t" . _cat_row( $category, $level );
 
-		echo $output;
-	} else {
-		return false;
+		unset($categories[$i]); // Prune the working set		
+		$count++;
+
+		if ( isset($children[$category->term_id]) )
+			cat_rows( $category->term_id, $level + 1, $categories, $page, $per_page, $count );
+
 	}
+
+	$output = ob_get_contents();
+	ob_end_clean();
+
+	$output = apply_filters('cat_rows', $output);
+
+	echo $output;
 }
 
 function _cat_row( $category, $level, $name_override = false ) {
Index: wp-admin/categories.php
===================================================================
--- wp-admin/categories.php	(revision 8072)
+++ wp-admin/categories.php	(working copy)
@@ -135,6 +135,24 @@
 
 <div class="tablenav">
 
+<?php
+$pagenum = absint( $_GET['pagenum'] );
+if ( empty($pagenum) )
+	$pagenum = 1;
+if( !$catsperpage || $catsperpage < 0 )
+	$catsperpage = 20;
+
+$page_links = paginate_links( array(
+	'base' => add_query_arg( 'pagenum', '%#%' ),
+	'format' => '',
+	'total' => ceil(wp_count_terms('category') / $catsperpage),
+	'current' => $pagenum
+));
+
+if ( $page_links )
+	echo "<div class='tablenav-pages'>$page_links</div>";
+?>
+
 <div class="alignleft">
 <input type="submit" value="<?php _e('Delete'); ?>" name="deleteit" class="button-secondary delete" />
 <?php wp_nonce_field('bulk-categories'); ?>
@@ -156,13 +174,19 @@
 	</thead>
 	<tbody id="the-list" class="list:cat">
 <?php
-cat_rows();
+$categories = array();
+cat_rows(0, 0, $categories, $pagenum, $catsperpage);
 ?>
 	</tbody>
 </table>
 </form>
 
 <div class="tablenav">
+
+<?php
+if ( $page_links )
+	echo "<div class='tablenav-pages'>$page_links</div>";
+?>
 <br class="clear" />
 </div>
 <br class="clear" />
