Index: wp-admin/admin-ajax.php
===================================================================
--- wp-admin/admin-ajax.php	(revision 17369)
+++ wp-admin/admin-ajax.php	(working copy)
@@ -1467,6 +1467,20 @@
 case 'time_format' :
 	die( date_i18n( sanitize_option( 'time_format', $_POST['date'] ) ) );
 	break;
+case 'detach_media' :
+	$post_id = intval( $_POST['post_id'] );
+	if ( !current_user_can( 'edit_post', $post_id ) )
+		die( '-1' );
+	$detached = $wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'post_type' => 'attachment', 'ID' => $post_id ) );
+	$html = _( '(Unattached)' ) . "<br />\n" .
+					"<a class=\"hide-if-no-js\" onclick=\"findPosts.open( 'media[]','$post_id' );return false;\" href=\"#the-list\">" . _( 'Attach' ) . "</a>";
+	$x = new WP_Ajax_Response();
+	$x->add( array(
+		'id' => $post_id,
+		'data' => $html
+	));
+	$x->send();
+	break;
 default :
 	do_action( 'wp_ajax_' . $_POST['action'] );
 	die('0');
Index: wp-admin/includes/class-wp-media-list-table.php
===================================================================
--- wp-admin/includes/class-wp-media-list-table.php	(revision 17369)
+++ wp-admin/includes/class-wp-media-list-table.php	(working copy)
@@ -79,7 +79,8 @@
 		$actions['delete'] = __( 'Delete Permanently' );
 		if ( $this->detached )
 			$actions['attach'] = __( 'Attach to a post' );
-
+		else
+			$actions['detach'] = __( 'Detach media' );
 		return $actions;
 	}
 
@@ -289,7 +290,8 @@
 ?>
 			<td <?php echo $attributes ?>>
 				<strong><a href="<?php echo get_edit_post_link( $post->post_parent ); ?>"><?php echo $title ?></a></strong>,
-				<?php echo get_the_time( __( 'Y/m/d' ) ); ?>
+				<?php echo get_the_time( __( 'Y/m/d' ) ); ?><br />
+				<a class="hide-if-no-js" onclick="detachMedia.detach(<?php echo $post->ID; ?>);return false;" href="#the-list"><?php _e( 'Detach' ); ?></a>
 			</td>
 <?php
 		} else {
Index: wp-admin/js/media.dev.js
===================================================================
--- wp-admin/js/media.dev.js	(revision 17369)
+++ wp-admin/js/media.dev.js	(working copy)
@@ -1,5 +1,5 @@
 
-var findPosts;
+var findPosts, detachMedia;
 (function($){
 	findPosts = {
 		open : function(af_name, af_val) {
@@ -72,6 +72,59 @@
 		}
 	};
 
+	detachMedia = {
+		detach : function(id) {
+			var post = {
+				post_id: id,
+				action: 'detach_media',
+				_ajax_nonce: $('#_ajax_nonce').val()
+			};
+			$.ajax({
+				type : 'POST',
+				url : ajaxurl,
+				data : post,
+				success : function(x) { detachMedia.show(x); },
+				error : function(r) { detachMedia.error(r); }
+			});
+		},
+
+		show : function(x) {
+
+			if ( typeof(x) == 'string' ) {
+				this.error({'responseText': x});
+				return;
+			}
+
+			var r = wpAjax.parseAjaxResponse(x);
+			if ( r.errors ) {
+				this.error({'responseText': wpAjax.broken});
+			}
+			r = r.responses[0];
+			$('#post-' + r.id + ' td.parent').html(r.data);
+
+			var count = $('.subsubsub .detached .count').html();
+			count = parseInt(count.substr(1, count.length - 2), 10);
+			$('.subsubsub .detached .count').html('(' + (count + 1) + ')');
+			
+			if ($('#message').length > 0) {
+				$('#message').html('<p>Detached 1 media file.</p>');
+			} else {
+				$('h2').after('<div id="message" class="updated below-h2"><p>Detached 1 media file.</p></div>');
+			}
+		},
+
+	  error : function(r) {
+			var er = r.statusText;
+
+			if ( r.responseText ) {
+				er = r.responseText.replace( /<.[^<>]*?>/g, '' );
+			}
+			if ( er ) {
+				$('#find-posts-response').html(er);
+			}
+		}
+	};
+
 	$(document).ready(function() {
 		$('#find-posts-submit').click(function(e) {
 			if ( '' == $('#find-posts-response').html() )
Index: wp-admin/upload.php
===================================================================
--- wp-admin/upload.php	(revision 17369)
+++ wp-admin/upload.php	(working copy)
@@ -89,6 +89,41 @@
 				exit;
 			}
 			break;
+		case 'detach':
+			$detach = array();
+			foreach ( (array) $_REQUEST['media'] as $att_id ) {
+				$att_id = (int) $att_id;
+
+				if ( !current_user_can( 'edit_post', $att_id ) )
+					continue;
+
+				$detach[] = $att_id;
+				clean_attachment_cache( $att_id );
+			}
+
+			if ( ! empty( $detach ) ) {
+				$parent_ids = $wpdb->get_col( $wpdb->prepare( "SELECT post_parent FROM $wpdb->posts WHERE post_type = 'attachment' AND ID IN ( $detach )" ) );
+				foreach ( $parent_ids as $parent_id ) {
+					if ( !current_user_can( 'edit_post', $parent_id ) )
+						wp_die( __( 'You are not allowed to edit this post.' ) );
+				}
+				
+				$detach = implode( ',', $detach );
+				$detached = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_parent = 0 WHERE post_type = 'attachment' AND ID IN ( $detach )" ) );
+			}
+
+			if ( isset( $detached ) ) {
+				$location = 'upload.php';
+				if ( $referer = wp_get_referer() ) {
+					if ( false !== strpos( $referer, 'upload.php' ) )
+						$location = $referer;
+				}
+
+				$location = add_query_arg( array( 'detached_media' => $detached ) , $location );
+				wp_redirect( $location );
+				exit;
+			}
+			break;
 		case 'trash':
 			foreach ( (array) $post_ids as $post_id ) {
 				if ( !current_user_can( 'delete_post', $post_id ) )
@@ -178,6 +213,12 @@
 	$_SERVER['REQUEST_URI'] = remove_query_arg(array('attached'), $_SERVER['REQUEST_URI']);
 }
 
+if ( isset($_GET['detached_media']) && (int) $_GET['detached_media'] ) {
+	$detached = (int) $_GET['detached_media'];
+	$message = sprintf( _n('Detached %d media file.', 'Detached %d media files.', $detached), $detached );
+	$_SERVER['REQUEST_URI'] = remove_query_arg(array('detached_media'), $_SERVER['REQUEST_URI']);
+}
+
 if ( isset($_GET['deleted']) && (int) $_GET['deleted'] ) {
 	$message = sprintf( _n( 'Media attachment permanently deleted.', '%d media attachments permanently deleted.', $_GET['deleted'] ), number_format_i18n( $_GET['deleted'] ) );
 	$_SERVER['REQUEST_URI'] = remove_query_arg(array('deleted'), $_SERVER['REQUEST_URI']);
