Index: src/bp-messages/bp-messages-functions.php
===================================================================
--- src/bp-messages/bp-messages-functions.php
+++ src/bp-messages/bp-messages-functions.php
@@ -366,6 +366,33 @@
 	return BP_Messages_Thread::is_valid( $thread_id );
 }
 
+/**
+ * Get the thread ID from a message ID.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  int $message_id ID of the message.
+ * @return int The ID of the thread if found, otherwise 0.
+ */
+function messages_get_message_thread_id( $message_id = 0 ) {
+	global $wpdb;
+
+	$bp = buddypress();
+
+	return (int) $wpdb->get_var( $wpdb->prepare( "SELECT thread_id FROM {$bp->messages->table_name_messages} WHERE id = %d", $message_id ) );
+}
+
+/**
+ * Is the 'Starred' private messages feature enabled?
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @return bool
+ */
+function bp_messages_is_starred_enabled() {
+	return (bool) apply_filters( 'bp_messages_enable_starred', true );
+}
+
 /** Messages Meta *******************************************************/
 
 /**
Index: src/bp-messages/bp-messages-loader.php
===================================================================
--- src/bp-messages/bp-messages-loader.php
+++ src/bp-messages/bp-messages-loader.php
@@ -67,6 +67,11 @@
 		);
 
 		parent::includes( $includes );
+
+		// Conditional includes
+		if ( bp_messages_is_starred_enabled() ) {
+			require $this->path . 'bp-messages/bp-messages-starred.php';
+		}
 	}
 
 	/**
@@ -164,6 +169,18 @@
 			'user_has_access' => bp_core_can_edit_settings()
 		);
 
+		if ( bp_messages_is_starred_enabled() ) {
+			$sub_nav[] = array(
+				'name'            => __( 'Starred', 'buddypress' ),
+				'slug'            => bp_get_messages_starred_slug(),
+				'parent_url'      => $messages_link,
+				'parent_slug'     => $this->slug,
+				'screen_function' => 'bp_messages_starred_screen',
+				'position'        => 11,
+				'user_has_access' => bp_core_can_edit_settings()
+			);
+		}
+
 		$sub_nav[] = array(
 			'name'            => __( 'Sent', 'buddypress' ),
 			'slug'            => 'sentbox',
@@ -241,6 +258,16 @@
 				'href'   => trailingslashit( $messages_link . 'inbox' )
 			);
 
+			// Starred
+			if ( bp_messages_is_starred_enabled() ) {
+				$wp_admin_nav[] = array(
+					'parent' => 'my-account-' . $this->id,
+					'id'     => 'my-account-' . $this->id . '-starred',
+					'title'  => __( 'Starred', 'buddypress' ),
+					'href'   => trailingslashit( $messages_link . bp_get_messages_starred_slug() )
+				);
+			}
+
 			// Sent Messages
 			$wp_admin_nav[] = array(
 				'parent' => 'my-account-' . $this->id,
Index: src/bp-messages/bp-messages-starred.php
new file mode 100644
===================================================================
--- /dev/null
+++ src/bp-messages/bp-messages-starred.php
@@ -0,0 +1,411 @@
+<?php
+/**
+ * Functions related to starring private messages.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+
+/** UTILITY **************************************************************/
+
+/**
+ * Function to determine if a message ID is starred.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  int $mid     The message ID
+ * @param  int $user_id The user ID
+ * @return bool
+ */
+function bp_messages_is_message_starred( $mid = 0, $user_id = 0 ) {
+	if ( empty( $user_id ) ) {
+		$user_id = bp_loggedin_user_id();
+	}
+
+	if ( empty( $mid ) ) {
+		return false;
+	}
+
+	$starred = array_flip( (array) bp_messages_get_meta( $mid, 'starred_by_user', false ) );
+
+	if ( isset( $starred[$user_id] ) ) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+/**
+ * Return the starred messages slug. Defaults to 'starred'.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @return string
+ */
+function bp_get_messages_starred_slug() {
+	/**
+	 * Filters the starred message slug.
+	 *
+	 * @since BuddyPress (2.3.0)
+	 *
+	 * @param string
+	 */
+	return sanitize_title( apply_filters( 'bp_get_messages_starred_slug', 'starred' ) );
+}
+
+/**
+ * Output the URL for deleting the current thread.
+ */
+function bp_messages_starred_action_link( $args = array() ) {
+	echo bp_get_messages_starred_action_link( $args );
+}
+	/**
+	 * Return the URL for deleting the current thread.
+	 *
+	 * @param array $args {
+	 *     Array of arguments.
+	 *     @type int    $user_id       The user ID. Defaults to the logged-in user ID.
+	 *     @type int    $thread_id     The message thread ID. Default: 0. If not zero, this takes precedence over
+	 *                                 $message_id.
+	 *     @type int    $message_id    The individual message ID. If on a single thread page, defaults to the
+	 *                                 current message ID in the message loop.
+	 *     @type bool   $link_only     Whether to return the link only. If false, returns link with markup.
+	 *                                 Default: false.
+	 *     @type string $string_unstar Link text for the 'unstar' action. Only applicable if $link_only is false.
+	 *     @type string $string_star   Link text for the 'star' action. Only applicable if $link_only is false.
+	 }
+	 * @return string
+	 */
+	function bp_get_messages_starred_action_link( $args = array() ) {
+		$r = bp_parse_args( $args, array(
+			'user_id'       => bp_loggedin_user_id(),
+			'thread_id'     => 0,
+			'message_id'    => (int) bp_get_the_thread_message_id(),
+			'link_only'     => false,
+			'string_unstar' => __( 'Unstar', 'buddypress' ),
+			'string_star'   => __( 'Star', 'buddypress' ),			
+		), 'messages_starred_action_link' );
+
+		$retval = $bulk_attr = '';
+
+		if ( 0 === $r['user_id'] ) {
+			return $retval;
+		}
+
+		// get user domain
+		if ( $r['user_id'] == bp_loggedin_user_id() ) {
+			$user_domain = bp_loggedin_user_domain();
+		} elseif ( $r['user_id'] == bp_displayed_user_domain() ) {
+			$user_domain = bp_displayed_user_domain();
+		} else {
+			$user_domain = bp_core_get_user_domain( $user_id );
+		}
+
+		// thread ID
+		if ( (int) $r['thread_id'] > 0 ) {
+			// see if we're in the loop
+			if ( bp_get_message_thread_id() == $r['thread_id'] ) {
+				// grab all message ids
+				$mids = wp_list_pluck( $GLOBALS['messages_template']->thread->messages, 'id' );
+
+				// make sure order is ASC
+				// order is DESC when used in the thread loop by default
+				$mids = array_reverse( $mids );
+
+			// pull up the thread
+			} else {
+				$thread = new BP_Messages_thread( $r['thread_id'] );
+				$mids = wp_list_pluck( $thread->messages, 'id' );
+			}
+
+			$is_starred = false;
+			$message_id = 0;
+			foreach ( $mids as $mid ) {
+				// try to find the first msg that is starred in a thread
+				if ( true === bp_messages_is_message_starred( $mid ) ) {
+					$is_starred = true;
+					$message_id = $mid;
+					break;
+				}
+			}
+
+			// no star, so default to first message in thread
+			if ( empty( $message_id ) ) {
+				$message_id = $mids[0];
+			}
+
+			// nonce
+			$nonce = wp_create_nonce( "bp-messages-star-{$message_id}" );
+
+			if ( $is_starred ) {
+				$action = 'unstar';
+				$bulk_attr = ' data-star-bulk="1"';
+				$retval = $user_domain . bp_get_messages_slug() . '/unstar/' . $message_id . '/' . $nonce . '/all/';
+			} else {
+				$action = 'star';
+				$retval = $user_domain . bp_get_messages_slug() . '/star/' . $message_id . '/' . $nonce . '/';
+			}
+
+		// message ID
+		} else {
+			$message_id = (int) $r['message_id'];
+			$is_starred = bp_messages_is_message_starred( $message_id );
+			$nonce      = wp_create_nonce( "bp-messages-star-{$message_id}" );
+
+			if ( $is_starred ) {
+				$action = 'unstar';
+				$retval = $user_domain . bp_get_messages_slug() . '/unstar/' . $message_id . '/' . $nonce . '/';
+			} else {
+				$action = 'star';
+				$retval = $user_domain . bp_get_messages_slug() . '/star/' . $message_id . '/' . $nonce . '/';
+			}
+		}
+
+		/**
+		 * Filters the starred action URL for starring / unstarring a message.
+		 *
+		 * @since BuddyPress (2.3.0)
+		 *
+		 * @param string $retval URL for starring / unstarring a message.
+		 * @param array  $r      Parsed link arguments. See $args in bp_get_messages_starred_action_link().
+		 */
+		$retval = esc_url( apply_filters( 'bp_get_messages_starred_action_linkonly', $retval, $r ) );
+		if ( true === (bool) $r['link_only'] ) {
+			return $retval;
+		}
+
+		/**
+		 * Filters the starred action link, including markup.
+		 *
+		 * @since BuddyPress (2.3.0)
+		 *
+		 * @param string $retval Link for starring / unstarring a message, including markup.
+		 * @param array  $r      Parsed link arguments. See $args in bp_get_messages_starred_action_link().
+		 */
+		return apply_filters( 'bp_get_messages_starred_action_link', '<a class="message-action-' . $action . '" data-star-status="' . $action .'" data-star-nonce="' . $nonce . '"' . $bulk_attr . ' data-message-id="' . esc_attr( (int) $message_id ) . '" href="' . $retval . '"><span class="icon"></span> <span class="screen-reader-text">' . $r['string_' . $action] . '</span></a>', $r );
+	}
+
+/**
+ * Save or delete message meta according to a message star's status.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  array $args {
+ *     Array of arguments.
+ *     @type string $action     The star action. Either 'star' or 'unstar'. Default: 'star'.
+ *     @type int    $message_id The message ID to star or unstar.  Default: 0.
+ *     @type int    $user_id    The user ID. Defaults to the logged-in user ID.
+ *     @type bool   $bulk       Whether to mark all messages in a thread as a certain action. Only relevant
+ *                              when $action is 'unstar' at the moment. Default: false.
+ * }
+ * @return bool
+ */
+function bp_messages_starred_set_action( $args = array() ) {
+	$r = wp_parse_args( $args, array(
+		'action'     => 'star',
+		'message_id' => 0,
+		'user_id'    => bp_loggedin_user_id(),
+		'bulk'       => false
+	) );
+
+	$thread_id = messages_get_message_thread_id( $r['message_id'] );
+	if ( empty( $thread_id ) ) {
+		return false;
+	}
+
+	if( ! messages_check_thread_access( $thread_id ) ) {
+		return false;
+	}
+
+	$is_starred = bp_messages_is_message_starred( $r['message_id'] );
+
+	// star
+	if ( 'star' == $r['action'] ) {
+		if ( true === $is_starred ) {
+			return true;
+		} else {
+			bp_messages_add_meta( $r['message_id'], 'starred_by_user', $r['user_id'] );
+			return true;
+		}
+	// unstar
+	} else {
+		// unstar one message
+		if ( false === $r['bulk'] ) {
+			if ( false === $is_starred ) {
+				return true;
+			} else {
+				bp_messages_delete_meta( $r['message_id'], 'starred_by_user', $r['user_id'] );
+				return true;
+			}
+
+		// unstar all messages in a thread
+		} else {
+			$thread = new BP_Messages_Thread( $thread_id );
+			$mids = wp_list_pluck( $thread->messages, 'id' );
+
+			foreach ( $mids as $mid ) {
+				if ( true === bp_messages_is_message_starred( $mid ) ) {
+					bp_messages_delete_meta( $mid, 'starred_by_user', $r['user_id'] );
+				}
+			}
+
+			return true;
+		}
+	}
+}
+
+/** SCREENS **************************************************************/
+
+/**
+ * Screen handler to display a user's "Starred" private messages page.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_messages_starred_screen() {
+	add_action( 'bp_template_content', 'bp_messages_starred_content' );
+
+	/**
+	 * Fires right before the loading of the "Starred" messages box.
+	 *
+	 * @since BuddyPress (2.3.0)
+	 */
+	do_action( 'bp_messages_screen_starred' );
+
+	bp_core_load_template( 'members/single/plugins' );
+}
+
+/**
+ * Screen content callback to display a user's "Starred" messages page.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_messages_starred_content() {
+	// add our message thread filter
+	add_filter( 'bp_after_has_message_threads_parse_args', 'bp_messages_filter_starred_message_threads' );
+
+	// load the message loop template part
+	bp_get_template_part( 'members/single/messages/messages-loop' );
+
+	// remove our filter
+	remove_filter( 'bp_after_has_message_threads_parse_args', 'bp_messages_filter_starred_message_threads' );
+}
+
+/**
+ * Filter message threads by those starred by the logged-in user.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  array $r Current message thread arguments.
+ * @return array
+ */
+function bp_messages_filter_starred_message_threads( $r = array() ) {
+	$r['user_id'] = 0;
+	$r['meta_query'] = array( array(
+		'key'   => 'starred_by_user',
+		'value' => bp_loggedin_user_id()
+	) );
+
+	return $r;
+}
+
+/** ACTIONS **************************************************************/
+
+/**
+ * Action handler to set a message's star status for those not using JS.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_messages_starred_action_handler() {
+	if ( ! bp_is_user_messages() ) {
+		return;
+	}
+
+	if ( false === ( bp_is_current_action( 'unstar' ) || bp_is_current_action( 'star' ) ) ) {
+		return;
+	}
+
+	if ( ! wp_verify_nonce( bp_action_variable( 1 ), 'bp-messages-star-' . bp_action_variable( 0 ) ) ) {
+		wp_die( "Oops!  That's a no-no!" );
+	}
+
+	// mark the star
+	$set = bp_messages_starred_set_action( array(
+		'action'     => bp_current_action(),
+		'message_id' => bp_action_variable(),
+		'bulk'       => (bool) bp_action_variable( 2 )
+	) );
+
+	// redirect back to previous screen
+	$redirect = wp_get_referer() ? wp_get_referer() : bp_loggedin_user_domain() . bp_get_messages_slug();
+	bp_core_redirect( $redirect );
+	die();
+}
+add_action( 'bp_actions', 'bp_messages_starred_action_handler' );
+
+/**
+ * AJAX callback to set a message's star status.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_messages_starred_ajax_handler() {
+	if ( empty( $_POST['message_id'] ) ) {
+		return;
+	}
+
+	check_ajax_referer( 'bp-messages-star-' . (int) $_POST['message_id'], 'nonce' );
+
+	$bulk = ! empty( $_POST['bulk'] ) ? true : false;
+
+	if ( true === bp_messages_starred_set_action( array(
+		'action'     => $_POST['star_status'],
+		'message_id' => (int) $_POST['message_id'],
+		'bulk'       => $bulk
+	 ) ) ) {
+		echo '1';
+		die();
+	}
+
+	echo '-1';
+	die();
+}
+add_action( 'wp_ajax_messages_starred', 'bp_messages_starred_ajax_handler' );
+
+
+/** HOOKS ****************************************************************/
+
+/**
+ * Enqueues the dashicons font on user private message pages.
+ *
+ * The dashicons font is used for the star / unstar icon.
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_messages_starred_enqueue_styles() {
+	if ( ! bp_is_user_messages() ) {
+		return;
+	}
+
+	wp_enqueue_style( 'dashicons' );
+}
+add_action( 'wp_enqueue_scripts', 'bp_messages_starred_enqueue_styles' );
+
+/**
+ * Add CSS class for the current message depending on starred status.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  array $retval Current CSS classes
+ * @return array
+ */
+function bp_messages_starred_message_css_class( $retval = array() ) {
+	if ( true === bp_messages_is_message_starred( bp_get_the_thread_message_id() ) ) {
+		$status = 'starred';
+	} else {
+		$status = 'not-starred';
+	}
+
+	// add css class based on star status for the current message
+	$retval[] = "message-{$status}";
+
+	return $retval;
+}
+add_filter( 'bp_get_the_thread_message_css_class', 'bp_messages_starred_message_css_class' );
Index: src/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php
===================================================================
--- src/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php
+++ src/bp-templates/bp-legacy/buddypress/members/single/messages/messages-loop.php
@@ -48,6 +48,11 @@
 					<th scope="col" class="thread-checkbox bulk-select-all"><label class="bp-screen-reader-text" for="select-all-messages"><?php _e( 'Select all', 'buddypress' ); ?></label><input id="select-all-messages" type="checkbox"></th>
 					<th scope="col" class="thread-from"><?php _e( 'From', 'buddypress' ); ?></th>
 					<th scope="col" class="thread-info"><?php _e( 'Subject', 'buddypress' ); ?></th>
+
+					<?php if ( bp_messages_is_starred_enabled() ) : ?>
+						<th scope="col" class="thread-star"><span class="message-action-star"><span class="icon"></span> <span class="screen-reader-text"><?php _e( 'Star', 'buddypress' ); ?></span></span></th>
+					<?php endif; ?>
+
 					<th scope="col" class="thread-options"><?php _e( 'Actions', 'buddypress' ); ?></th>
 				</tr>
 			</thead>
@@ -91,6 +96,12 @@
 						 */
 						do_action( 'bp_messages_inbox_list_item' ); ?>
 
+						<?php if ( bp_messages_is_starred_enabled() ) : ?>
+							<td class="thread-star">
+								<?php bp_messages_starred_action_link( array( 'thread_id' => bp_get_message_thread_id() ) ); ?>
+							</td>
+						<?php endif; ?>
+
 						<td class="thread-options">
 							<?php if ( bp_message_thread_has_unread() ) : ?>
 								<a class="read" href="<?php bp_the_message_thread_mark_read_url();?>"><?php _e( 'Read', 'buddypress' ); ?></a>
Index: src/bp-templates/bp-legacy/buddypress/members/single/messages/single.php
===================================================================
--- src/bp-templates/bp-legacy/buddypress/members/single/messages/single.php
+++ src/bp-templates/bp-legacy/buddypress/members/single/messages/single.php
@@ -69,6 +69,12 @@
 
 					<span class="activity"><?php bp_the_thread_message_time_since(); ?></span>
 
+					<?php if ( bp_messages_is_starred_enabled() ) : ?>
+						<div class="message-star-actions">
+							<?php bp_messages_starred_action_link(); ?>
+						</div>
+					<?php endif; ?>
+
 					<?php
 
 					/** This action is documented in bp-templates/bp-legacy/buddypress-functions.php */
Index: src/bp-templates/bp-legacy/css/buddypress.css
===================================================================
--- src/bp-templates/bp-legacy/css/buddypress.css
+++ src/bp-templates/bp-legacy/css/buddypress.css
@@ -1445,6 +1445,39 @@
 	margin: 0 20px;
 }
 
+.message-metadata {
+	position: relative;
+}
+.message-star-actions {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+a.message-action-star,
+a.message-action-unstar {
+	text-decoration: none;
+	outline: none;
+}
+a.message-action-star {
+	opacity: .7;
+}
+a.message-action-star:hover {
+	opacity: 1;
+}
+.message-action-star span.icon:before,
+.message-action-unstar span.icon:before {
+	font-family: dashicons;
+	font-size: 18px;
+}
+.message-action-star span.icon:before {
+	color: #aaa;
+	content: "\f154";
+}
+.message-action-unstar span.icon:before {
+	color: #FCDD77;
+	content: "\f155";
+}
+
 /*--------------------------------------------------------------
 3.10 - Extended Profiles
 --------------------------------------------------------------*/
Index: src/bp-templates/bp-legacy/js/buddypress.js
===================================================================
--- src/bp-templates/bp-legacy/js/buddypress.js
+++ src/bp-templates/bp-legacy/js/buddypress.js
@@ -1578,6 +1578,37 @@
 		jq('#messages-bulk-manage').attr('disabled', jq(this).val().length <= 0);
 	});
 
+	/* Star action function */
+	starAction = function() {
+		var link = jq(this);
+
+		jq.post( ajaxurl, {
+			action: 'messages_starred',
+			'message_id': link.data('message-id'),
+			'star_status': link.data('star-status'),
+			'nonce': link.data('star-nonce'),
+			'bulk': link.data('star-bulk')
+		},
+		function(response) {
+			if ( response ) {
+				if ( 'unstar' === link.data('star-status') ) {
+					link.data('star-status', 'star');
+					link.removeClass('message-action-unstar').addClass('message-action-star');
+				} else {
+					link.data('star-status', 'unstar');
+					link.removeClass('message-action-star').addClass('message-action-unstar');
+				}
+			}
+		});
+		return false;
+	}
+
+	/* Star actions */
+	jq('#message-threads').on('click', 'td.thread-star a', starAction );
+	jq('#message-thread').on('click', '.message-star-actions a', starAction );
+
+	/** Notifications **********************************************/
+
 	/* Selecting/Deselecting all notifications */
 	jq('#select-all-notifications').click(function(event) {
 		if( this.checked ) {
