diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 0b9110d35fae59c3c5b3c63e8103e5e14cfb57e5..2fdb7562515e248528b9259efdec966ab7d24a7d 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -17,6 +17,7 @@ class Dispatcher
     switch page
       when 'projects:issues:index'
         Issues.init()
+        Issuable.init()
         shortcut_handler = new ShortcutsNavigation()
       when 'projects:issues:show'
         new Issue()
@@ -57,7 +58,7 @@ class Dispatcher
         new ZenMode()
       when 'projects:merge_requests:index'
         shortcut_handler = new ShortcutsNavigation()
-        MergeRequests.init()
+        Issuable.init()
       when 'dashboard:activity'
         new Activities()
       when 'dashboard:projects:starred'
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 641141072f42167727e9b43fb266362b1be27c1a..e5204f9dee970ab7c60ba3f8c500173e2fae3fc0 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -386,13 +386,13 @@ class GitLabDropdown
       else
         selectedObject
     else
-      if !value?
-        field.remove()
-
-      if not @options.multiSelect
+      if not @options.multiSelect or el.hasClass('dropdown-clear-active')
         @dropdown.find(".#{ACTIVE_CLASS}").removeClass ACTIVE_CLASS
         @dropdown.parent().find("input[name='#{fieldName}']").remove()
 
+      if !value?
+        field.remove()
+
       # Toggle active class for the tick mark
       el.addClass ACTIVE_CLASS
 
diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee
new file mode 100644
index 0000000000000000000000000000000000000000..afffed63ac57ec9c916111e7d9853040cbf18d46
--- /dev/null
+++ b/app/assets/javascripts/issuable.js.coffee
@@ -0,0 +1,84 @@
+@Issuable =
+  init: ->
+    Issuable.initTemplates()
+    Issuable.initSearch()
+
+  initTemplates: ->
+    Issuable.labelRow = _.template(
+      '<% _.each(labels, function(label){ %>
+        <span class="label-row">
+          <a href="#"><span class="label color-label has-tooltip" style="background-color: <%= label.color %>; color: <%= label.text_color %>" title="<%= _.escape(label.description) %>" data-container="body"><%= _.escape(label.title) %></span></a>
+        </span>
+      <% }); %>'
+    )
+
+  initSearch: ->
+    @timer = null
+    $('#issue_search')
+      .off 'keyup'
+      .on 'keyup', ->
+        clearTimeout(@timer)
+        @timer = setTimeout( ->
+          Issuable.filterResults $('#issue_search_form')
+        , 500)
+
+  toggleLabelFilters: ->
+    $filteredLabels = $('.filtered-labels')
+    if $filteredLabels.find('.label-row').length > 0
+      $filteredLabels.removeClass('hidden')
+    else
+      $filteredLabels.addClass('hidden')
+
+  filterResults: (form) =>
+    formData = form.serialize()
+
+    $('.issues-holder, .merge-requests-holder').css('opacity', '0.5')
+    formAction = form.attr('action')
+    issuesUrl = formAction
+    issuesUrl += ("#{if formAction.indexOf('?') < 0 then '?' else '&'}")
+    issuesUrl += formData
+    $.ajax
+      type: 'GET'
+      url: formAction
+      data: formData
+      complete: ->
+        $('.issues-holder, .merge-requests-holder').css('opacity', '1.0')
+      success: (data) ->
+        $('.issues-holder, .merge-requests-holder').html(data.html)
+        # Change url so if user reload a page - search results are saved
+        history.replaceState {page: issuesUrl}, document.title, issuesUrl
+        Issuable.reload()
+        Issuable.updateStateFilters()
+        $filteredLabels = $('.filtered-labels')
+
+        if typeof Issuable.labelRow is 'function'
+          $filteredLabels.html(Issuable.labelRow(data))
+
+        Issuable.toggleLabelFilters()
+
+      dataType: "json"
+
+  reload: ->
+    if Issues.created
+      Issues.initChecks()
+
+    $('#filter_issue_search').val($('#issue_search').val())
+
+  updateStateFilters: ->
+    stateFilters =  $('.issues-state-filters')
+    newParams = {}
+    paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search']
+
+    for paramKey in paramKeys
+      newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
+
+    if stateFilters.length
+      stateFilters.find('a').each ->
+        initialUrl = gl.utils.removeParamQueryString($(this).attr('href'), 'label_name[]')
+        labelNameValues = gl.utils.getParameterValues('label_name[]')
+        if labelNameValues
+          labelNameQueryString = ("label_name[]=#{value}" for value in labelNameValues).join('&')
+          newUrl = "#{gl.utils.mergeUrlParams(newParams, initialUrl)}&#{labelNameQueryString}"
+        else
+          newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
+        $(this).attr 'href', newUrl
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
index 0d9f2094c2a6d56d0c245de319222f4883eff822..3330e6c68aded1a471a45bbb9be51315e39db664 100644
--- a/app/assets/javascripts/issues.js.coffee
+++ b/app/assets/javascripts/issues.js.coffee
@@ -1,6 +1,6 @@
 @Issues =
   init: ->
-    Issues.initSearch()
+    Issues.created = true
     Issues.initChecks()
 
     $("body").on "ajax:success", ".close_issue, .reopen_issue", ->
@@ -15,10 +15,6 @@
         else
           $(this).html totalIssues - 1
 
-  reload: ->
-    Issues.initChecks()
-    $('#filter_issue_search').val($('#issue_search').val())
-
   initChecks: ->
     $(".check_all_issues").click ->
       $(".selected_issue").prop("checked", @checked)
@@ -26,51 +22,6 @@
 
     $(".selected_issue").bind "change", Issues.checkChanged
 
-  # Update state filters if present in page
-  updateStateFilters: ->
-    stateFilters =  $('.issues-state-filters')
-    newParams = {}
-    paramKeys = ['author_id', 'label_name', 'milestone_title', 'assignee_id', 'issue_search']
-
-    for paramKey in paramKeys
-      newParams[paramKey] = gl.utils.getUrlParameter(paramKey) or ''
-
-    if stateFilters.length
-      stateFilters.find('a').each ->
-        initialUrl = $(this).attr 'href'
-        $(this).attr 'href', gl.utils.mergeUrlParams(newParams, initialUrl)
-
-  # Make sure we trigger ajax request only after user stop typing
-  initSearch: ->
-    @timer = null
-    $("#issue_search").keyup ->
-      clearTimeout(@timer)
-      @timer = setTimeout( ->
-        Issues.filterResults $("#issue_search_form")
-      , 500)
-
-  filterResults: (form) =>
-    $('.issues-holder, .merge-requests-holder').css("opacity", '0.5')
-    formAction = form.attr('action')
-    formData = form.serialize()
-    issuesUrl = formAction
-    issuesUrl += ("#{if formAction.indexOf("?") < 0 then '?' else '&'}")
-    issuesUrl += formData
-
-    $.ajax
-      type: "GET"
-      url: formAction
-      data: formData
-      complete: ->
-        $('.issues-holder, .merge-requests-holder').css("opacity", '1.0')
-      success: (data) ->
-        $('.issues-holder, .merge-requests-holder').html(data.html)
-        # Change url so if user reload a page - search results are saved
-        history.replaceState {page: issuesUrl}, document.title, issuesUrl
-        Issues.reload()
-        Issues.updateStateFilters()
-      dataType: "json"
-
   checkChanged: ->
     checked_issues = $(".selected_issue:checked")
     if checked_issues.length > 0
diff --git a/app/assets/javascripts/labels_select.js.coffee b/app/assets/javascripts/labels_select.js.coffee
index 1131492b7aedde1113f57ba8392256f5e9f3229b..021ade73d445b5102439012395fa739801d5fffb 100644
--- a/app/assets/javascripts/labels_select.js.coffee
+++ b/app/assets/javascripts/labels_select.js.coffee
@@ -6,7 +6,7 @@ class @LabelsSelect
       labelUrl = $dropdown.data('labels')
       issueUpdateURL = $dropdown.data('issueUpdate')
       selectedLabel = $dropdown.data('selected')
-      if selectedLabel?
+      if selectedLabel? and not $dropdown.hasClass 'js-multiselect'
         selectedLabel = selectedLabel.split(',')
       newLabelField = $('#new_label_name')
       newColorField = $('#new_label_color')
@@ -16,6 +16,7 @@ class @LabelsSelect
       abilityName = $dropdown.data('ability-name')
       $selectbox = $dropdown.closest('.selectbox')
       $block = $selectbox.closest('.block')
+      $form = $dropdown.closest('form')
       $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon span')
       $value = $block.find('.value')
       $loading = $block.find('.block-loading').fadeOut()
@@ -171,7 +172,7 @@ class @LabelsSelect
             .find('a')
             .each((i) ->
               setTimeout(=>
-                glAnimate($(@), 'pulse')
+                gl.animate.animate($(@), 'pulse')
               ,200 * i
               )
             )
@@ -200,16 +201,21 @@ class @LabelsSelect
             callback data
 
         renderRow: (label) ->
-          selectedClass = ''
-          if $selectbox.find("input[type='hidden']\
-            [name='#{$dropdown.data('field-name')}']\
-            [value='#{label.id}']").length
-            selectedClass = 'is-active'
+          removesAll = label.id is 0 or not label.id?
+
+          selectedClass = []
+          if $form.find("input[type='hidden']\
+            [name='#{$dropdown.data('fieldName')}']\
+            [value='#{this.id(label)}']").length
+            selectedClass.push 'is-active'
+
+          if $dropdown.hasClass('js-multiselect') and removesAll
+            selectedClass.push 'dropdown-clear-active'
 
           color = if label.color? then "<span class='dropdown-label-box' style='background-color: #{label.color}'></span>" else ""
 
           "<li>
-            <a href='#' class='#{selectedClass}'>
+            <a href='#' class='#{selectedClass.join(' ')}'>
               #{color}
               #{_.escape(label.title)}
             </a>
@@ -219,37 +225,56 @@ class @LabelsSelect
           fields: ['title']
         selectable: true
 
-        toggleLabel: (selected) ->
+        toggleLabel: (selected, el) ->
+          selected_labels = $('.js-label-select').siblings('.dropdown-menu-labels').find('.is-active')
+
           if selected and selected.title?
-            selected.title
+            if selected_labels.length > 1
+              "#{selected.title} +#{selected_labels.length - 1} more"
+            else
+              selected.title
+          else if not selected and selected_labels.length isnt 0
+            if selected_labels.length > 1
+              "#{$(selected_labels[0]).text()} +#{selected_labels.length - 1} more"
+            else if selected_labels.length is 1
+              $(selected_labels).text()
           else
             defaultLabel
         fieldName: $dropdown.data('field-name')
         id: (label) ->
-          if label.isAny?
-            ''
-          else if $dropdown.hasClass "js-filter-submit"
+          if $dropdown.hasClass("js-filter-submit") and not label.isAny?
             label.title
           else
             label.id
 
         hidden: ->
+          page = $('body').data 'page'
+          isIssueIndex = page is 'projects:issues:index'
+          isMRIndex = page is 'projects:merge_requests:index'
+
           $selectbox.hide()
           # display:block overrides the hide-collapse rule
           $value.removeAttr('style')
           if $dropdown.hasClass 'js-multiselect'
-            saveLabelData()
+            if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
+              selectedLabels = $dropdown
+                .closest('form')
+                .find("input:hidden[name='#{$dropdown.data('fieldName')}']")
+              Issuable.filterResults $dropdown.closest('form')
+            else if $dropdown.hasClass('js-filter-submit')
+              $dropdown.closest('form').submit()
+            else
+              saveLabelData()
 
         multiSelect: $dropdown.hasClass 'js-multiselect'
         clicked: (label) ->
           page = $('body').data 'page'
           isIssueIndex = page is 'projects:issues:index'
-          isMRIndex = page is page is 'projects:merge_requests:index'
-
+          isMRIndex = page is 'projects:merge_requests:index'
           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
-            selectedLabel = label.title
-
-            Issues.filterResults $dropdown.closest('form')
+            if not $dropdown.hasClass 'js-multiselect'
+              selectedLabel = label.title
+              Issuable.filterResults $dropdown.closest('form')
           else if $dropdown.hasClass 'js-filter-submit'
             $dropdown.closest('form').submit()
           else
diff --git a/app/assets/javascripts/lib/animate.js.coffee b/app/assets/javascripts/lib/animate.js.coffee
index 8f892b5a2b9cc4abc0398cd7ccc33aeaefa63f1b..ec3b44d61263374ce7e5d8b5f01535cd0afbc3bd 100644
--- a/app/assets/javascripts/lib/animate.js.coffee
+++ b/app/assets/javascripts/lib/animate.js.coffee
@@ -1,13 +1,39 @@
 ((w) -> 
+  if not w.gl? then w.gl = {}
+  if not gl.animate? then gl.animate = {}
 
-  w.glAnimate = ($el, animation, done) ->
+  gl.animate.animate = ($el, animation, options, done) ->
+    if options?.cssStart?
+      $el.css(options.cssStart)
     $el
-      .removeClass()
+      .removeClass(animation + ' animated')
       .addClass(animation + ' animated')
       .one 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', ->
-        $(this).removeClass()
+        $(this).removeClass(animation + ' animated')
+        if done?
+          done()
+        if options?.cssEnd?
+          $el.css(options.cssEnd)
         return
     return
-  return
 
+  gl.animate.animateEach = ($els, animation, time, options, done) ->
+    dfd = $.Deferred()
+    if not $els.length
+      dfd.resolve()
+    $els.each((i) ->
+      setTimeout(=>
+        $this = $(@)
+        gl.animate.animate($this, animation, options, =>
+          if i is $els.length - 1
+            dfd.resolve()
+            if done?
+              done()
+        )
+      ,time * i
+      )
+      return
+    )
+    return dfd.promise()
+  return 
 ) window
\ No newline at end of file
diff --git a/app/assets/javascripts/lib/url_utility.js.coffee b/app/assets/javascripts/lib/url_utility.js.coffee
index abd556e0b4e07eb20f77d242cc98a459267f74d1..6a00932c028ff23577a13f51c89efe348b7d3491 100644
--- a/app/assets/javascripts/lib/url_utility.js.coffee
+++ b/app/assets/javascripts/lib/url_utility.js.coffee
@@ -3,16 +3,20 @@
   w.gl ?= {}
   w.gl.utils ?= {}
 
-  w.gl.utils.getUrlParameter = (sParam) ->
+  # Returns an array containing the value(s) of the
+  # of the key passed as an argument
+  w.gl.utils.getParameterValues = (sParam) ->
     sPageURL = decodeURIComponent(window.location.search.substring(1))
     sURLVariables = sPageURL.split('&')
     sParameterName = undefined
+    values = []
     i = 0
     while i < sURLVariables.length
       sParameterName = sURLVariables[i].split('=')
       if sParameterName[0] is sParam
-        return if sParameterName[1] is undefined then true else sParameterName[1]
+        values.push(sParameterName[1])
       i++
+    values
 
   # #
   #  @param {Object} params - url keys and value to merge
@@ -28,4 +32,12 @@
         newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}"
     newUrl
 
+  # removes parameter query string from url. returns the modified url
+  w.gl.utils.removeParamQueryString = (url, param) ->
+    url = decodeURIComponent(url)
+    urlVariables = url.split('&')
+    (
+      variables for variables in urlVariables when variables.indexOf(param) is -1
+    ).join('&')
+
 ) window
diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee
deleted file mode 100644
index b3c73ffce5d1c0f111b7acdf0db2a82a1edde403..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/merge_requests.js.coffee
+++ /dev/null
@@ -1,35 +0,0 @@
-#
-# * Filter merge requests
-#
-@MergeRequests =
-  init: ->
-    MergeRequests.initSearch()
-
-  # Make sure we trigger ajax request only after user stop typing
-  initSearch: ->
-    @timer = null
-    $("#issue_search").keyup ->
-      clearTimeout(@timer)
-      @timer = setTimeout(MergeRequests.filterResults, 500)
-
-  filterResults: =>
-    form = $("#issue_search_form")
-    search = $("#issue_search").val()
-    $('.merge-requests-holder').css("opacity", '0.5')
-    issues_url = form.attr('action') + '?' + form.serialize()
-
-    $.ajax
-      type: "GET"
-      url: form.attr('action')
-      data: form.serialize()
-      complete: ->
-        $('.merge-requests-holder').css("opacity", '1.0')
-      success: (data) ->
-        $('.merge-requests-holder').html(data.html)
-        # Change url so if user reload a page - search results are saved
-        history.replaceState {page: issues_url}, document.title, issues_url
-        MergeRequests.reload()
-      dataType: "json"
-
-  reload: ->
-    $('#filter_issue_search').val($('#issue_search').val())
diff --git a/app/assets/javascripts/milestone_select.js.coffee b/app/assets/javascripts/milestone_select.js.coffee
index 04fd5cf37bdc3824f714439ba0445265c9e37518..345a0e447af333a705d2c957d027daa93567e90b 100644
--- a/app/assets/javascripts/milestone_select.js.coffee
+++ b/app/assets/javascripts/milestone_select.js.coffee
@@ -97,7 +97,7 @@ class @MilestoneSelect
               selectedMilestone = selected.name
             else
               selectedMilestone = ''
-            Issues.filterResults $dropdown.closest('form')
+            Issuable.filterResults $dropdown.closest('form')
           else if $dropdown.hasClass('js-filter-submit')
             $dropdown.closest('form').submit()
           else
diff --git a/app/assets/javascripts/users_select.js.coffee b/app/assets/javascripts/users_select.js.coffee
index a7e934936e9387cd85b935ee6993d7ab20cc6b5b..b80b1b861ccca05379b7a6864c0a8b79f33cae0b 100644
--- a/app/assets/javascripts/users_select.js.coffee
+++ b/app/assets/javascripts/users_select.js.coffee
@@ -158,7 +158,7 @@ class @UsersSelect
 
           if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
             selectedId = user.id
-            Issues.filterResults $dropdown.closest('form')
+            Issuable.filterResults $dropdown.closest('form')
           else if $dropdown.hasClass 'js-filter-submit'
             $dropdown.closest('form').submit()
           else
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 85d5b52fa058711ab4a72551de4f73ffc8873637..e86428147ef0521cc35466277647b135eb3c41c5 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -33,14 +33,15 @@ class Projects::IssuesController < Projects::ApplicationController
     end
 
     @issues = @issues.page(params[:page])
-    @label = @project.labels.find_by(title: params[:label_name])
+    @labels = @project.labels.where(title: params[:label_name])
 
     respond_to do |format|
       format.html
       format.atom { render layout: false }
       format.json do
         render json: {
-          html: view_to_html_string("projects/issues/_issues")
+          html: view_to_html_string("projects/issues/_issues"),
+          labels: @labels.as_json(methods: :text_color)
         }
       end
     end
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 3e0cfc6aa657388b747a7c1e9fd8ab1a8cbc6ee2..1388ea9d66c2ebb09442511e4342b24db6526584 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -38,13 +38,14 @@ class Projects::MergeRequestsController < Projects::ApplicationController
     @merge_requests = @merge_requests.page(params[:page])
     @merge_requests = @merge_requests.preload(:target_project)
 
-    @label = @project.labels.find_by(title: params[:label_name])
+    @labels = @project.labels.where(title: params[:label_name])
 
     respond_to do |format|
       format.html
       format.json do
         render json: {
-          html: view_to_html_string("projects/merge_requests/_merge_requests")
+          html: view_to_html_string("projects/merge_requests/_merge_requests"),
+          labels: @labels.as_json(methods: :text_color)
         }
       end
     end
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index f1df6832bf661eda41d1a811b1614b5901950184..5eb1d3f5aac7fc547d58fafae8b941f78539550f 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -117,7 +117,7 @@ class IssuableFinder
   end
 
   def filter_by_no_label?
-    labels? && params[:label_name] == Label::None.title
+    labels? && params[:label_name].include?(Label::None.title)
   end
 
   def labels
@@ -278,7 +278,9 @@ class IssuableFinder
       end
     end
 
-    items
+    # When filtering by multiple labels we may end up duplicating issues (if one
+    # has multiple labels). This ensures we only return unique issues.
+    items.distinct
   end
 
   def label_names
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 16e5b8ac22311d7e80dbc0b5719cb11cea6103d6..3e0074da39420974435ad6958f9737d57e3228d3 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -254,11 +254,11 @@ module ApplicationHelper
 
   def page_filter_path(options = {})
     without = options.delete(:without)
+    add_label = options.delete(:label)
 
     exist_opts = {
       state: params[:state],
       scope: params[:scope],
-      label_name: params[:label_name],
       milestone_title: params[:milestone_title],
       assignee_id: params[:assignee_id],
       author_id: params[:author_id],
@@ -275,6 +275,13 @@ module ApplicationHelper
 
     path = request.path
     path << "?#{options.to_param}"
+    if add_label
+      if params[:label_name].present? and params[:label_name].respond_to?('any?')
+        params[:label_name].each do |label|
+          path << "&label_name[]=#{label}"
+        end
+      end
+    end
     path
   end
 
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 49b6b79ce35e68be442713a093d3eab224cc7424..3947421728604a976bc8c0dbb91ee13b641ea77f 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -16,6 +16,25 @@ module IssuablesHelper
     base_issuable_scope(issuable).where('iid > ?', issuable.iid).last
   end
 
+  def multi_label_name(current_labels, default_label)
+    # current_labels may be a string from before
+    if current_labels.is_a?(Array)
+      if current_labels.count > 1
+        "#{current_labels[0]} +#{current_labels.count - 1} more"
+      else
+        current_labels[0]
+      end
+    elsif current_labels.is_a?(String)
+      if current_labels.nil? || current_labels.empty?
+        default_label
+      else
+        current_labels
+      end
+    else
+      default_label
+    end
+  end
+
   def issuable_json_path(issuable)
     project = issuable.project
 
diff --git a/app/models/label.rb b/app/models/label.rb
index 55c01cae76261939656170c600f719702f65b101..60bdce32952ed15791d076cb00dd02b3ce3e98e4 100644
--- a/app/models/label.rb
+++ b/app/models/label.rb
@@ -113,6 +113,10 @@ class Label < ActiveRecord::Base
     template
   end
 
+  def text_color
+    LabelsHelper::text_color_for_bg(self.color)
+  end
+
   private
 
   def label_format_reference(format = :id)
diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml
index b38c5e18efba387eee30a26316c1c6a006c698a6..9ce5562e6673b87cbaf5f15eb3d97ee32c8dbcd5 100644
--- a/app/views/shared/_label_row.html.haml
+++ b/app/views/shared/_label_row.html.haml
@@ -2,4 +2,4 @@
   %span.label-name
     = link_to_label(label, tooltip: false)
   %span.prepend-left-10
-    = markdown(label.description, pipeline: :single_line)
+    = markdown(label.description, pipeline: :single_line)
\ No newline at end of file
diff --git a/app/views/shared/_labels_row.html.haml b/app/views/shared/_labels_row.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..dc89e36419cd462d539974cf1c4ee155a57dff9c
--- /dev/null
+++ b/app/views/shared/_labels_row.html.haml
@@ -0,0 +1,3 @@
+- labels.each do |label|
+  %span.label-row
+    = link_to_label(label, tooltip: false)
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 921eaefd79ad2e683224d86dbf8a2de0c7531f76..ade0a56b2e7f199a010db125eeee7f1357f9135d 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -46,9 +46,10 @@
           .filter-item.inline
             = button_tag "Update issues", class: "btn update_selected_issues btn-save"
 
-- if @label
-  .gray-content-block.second-block
-    = render "shared/label_row", label: @label
+  - if !@labels.nil?
+    .gray-content-block.second-block.filtered-labels{ class: ("hidden" if !@labels.any?) }
+      - if @labels.any?
+        = render "shared/labels_row", labels: @labels
 
 :javascript
   new UsersSelect();
diff --git a/app/views/shared/issuable/_label_dropdown.html.haml b/app/views/shared/issuable/_label_dropdown.html.haml
index f722e61eeac15dc351776b434cdeadfdf1a2a83f..3eaa45258f0ea591d5a0906553802d44016e9438 100644
--- a/app/views/shared/issuable/_label_dropdown.html.haml
+++ b/app/views/shared/issuable/_label_dropdown.html.haml
@@ -1,9 +1,11 @@
 - if params[:label_name].present?
-  = hidden_field_tag(:label_name, params[:label_name])
+  - if params[:label_name].respond_to?('any?')
+    - params[:label_name].each do |label|
+      = hidden_field_tag "label_name[]", label, id: nil
 .dropdown
-  %button.dropdown-menu-toggle.js-label-select.js-filter-submit.js-extra-options{type: "button", data: {toggle: "dropdown", field_name: "label_name", show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}}
+  %button.dropdown-menu-toggle.js-label-select.js-filter-submit.js-multiselect.js-extra-options{type: "button", data: {toggle: "dropdown", field_name: "label_name[]", show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}}
     %span.dropdown-toggle-text
-      = h(params[:label_name].presence || "Label")
+      = h(multi_label_name(params[:label_name], "Label"))
     = icon('chevron-down')
   .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
     .dropdown-page-one
diff --git a/app/views/shared/issuable/_nav.html.haml b/app/views/shared/issuable/_nav.html.haml
index a6970b7eebbeb115edec69f555717c87fce14f01..1d9b09a5ef1429176bc912d53b24b7579337c644 100644
--- a/app/views/shared/issuable/_nav.html.haml
+++ b/app/views/shared/issuable/_nav.html.haml
@@ -4,22 +4,22 @@
   - else
     - page_context_word = 'issues'
   %li{class: ("active" if params[:state] == 'opened')}
-    = link_to page_filter_path(state: 'opened'), title: "Filter by #{page_context_word} that are currently opened." do
+    = link_to page_filter_path(state: 'opened', label: true), title: "Filter by #{page_context_word} that are currently opened." do
       #{state_filters_text_for(:opened, @project)}
 
   - if defined?(type) && type == :merge_requests
     %li{class: ("active" if params[:state] == 'merged')}
-      = link_to page_filter_path(state: 'merged'), title: 'Filter by merge requests that are currently merged.' do
+      = link_to page_filter_path(state: 'merged', label: true), title: 'Filter by merge requests that are currently merged.' do
         #{state_filters_text_for(:merged, @project)}
 
     %li{class: ("active" if params[:state] == 'closed')}
-      = link_to page_filter_path(state: 'closed'), title: 'Filter by merge requests that are currently closed and unmerged.' do
+      = link_to page_filter_path(state: 'closed', label: true), title: 'Filter by merge requests that are currently closed and unmerged.' do
         #{state_filters_text_for(:closed, @project)}
   - else
     %li{class: ("active" if params[:state] == 'closed')}
-      = link_to page_filter_path(state: 'closed'), title: 'Filter by issues that are currently closed.' do
+      = link_to page_filter_path(state: 'closed', label: true), title: 'Filter by issues that are currently closed.' do
         #{state_filters_text_for(:closed, @project)}
 
   %li{class: ("active" if params[:state] == 'all')}
-    = link_to page_filter_path(state: 'all'), title: "Show all #{page_context_word}." do
+    = link_to page_filter_path(state: 'all', label: true), title: "Show all #{page_context_word}." do
       #{state_filters_text_for(:all, @project)}
diff --git a/features/project/issues/filter_labels.feature b/features/project/issues/filter_labels.feature
index e07f8053fb7ddffaa80cd6faa6302d5151fa0695..49d7a3b9af248d1888539d7d6fa416f1457f0d71 100644
--- a/features/project/issues/filter_labels.feature
+++ b/features/project/issues/filter_labels.feature
@@ -12,6 +12,7 @@ Feature: Project Issues Filter Labels
   @javascript
   Scenario: I filter by one label
     Given I click link "bug"
+    And I click "dropdown close button"
     Then I should see "Bugfix1" in issues list
     And I should see "Bugfix2" in issues list
     And I should not see "Feature1" in issues list
diff --git a/features/steps/project/issues/filter_labels.rb b/features/steps/project/issues/filter_labels.rb
index 6d50501a722d05a7daa33493ef7782ae752ff654..d82c68569182e2d0d6e03da21d6f91d109abaaee 100644
--- a/features/steps/project/issues/filter_labels.rb
+++ b/features/steps/project/issues/filter_labels.rb
@@ -32,6 +32,10 @@ class Spinach::Features::ProjectIssuesFilterLabels < Spinach::FeatureSteps
     page.find('.js-label-select').click
     sleep 0.5
     execute_script("$('.dropdown-menu-labels li:contains(\"bug\") a').click()")
+  end
+
+  step 'I click "dropdown close button"' do
+    page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
     sleep 2
   end
 
diff --git a/spec/features/issues/filter_by_labels_spec.rb b/spec/features/issues/filter_by_labels_spec.rb
new file mode 100644
index 0000000000000000000000000000000000000000..7944403f874ee2ebc06292998de3de101f361a6e
--- /dev/null
+++ b/spec/features/issues/filter_by_labels_spec.rb
@@ -0,0 +1,172 @@
+require 'rails_helper'
+
+feature 'Issue filtering by Labels', feature: true do
+  let(:project) { create(:project, :public) }
+  let!(:user)   { create(:user)}
+  let!(:label)  { create(:label, project: project) }
+
+  before do
+    ['bug', 'feature', 'enhancement'].each do |title|
+      create(:label,
+             project: project,
+             title: title)
+    end
+
+    issue1 = create(:issue, title: "Bugfix1", project: project)
+    issue1.labels << project.labels.find_by(title: 'bug')
+
+    issue2 = create(:issue, title: "Bugfix2", project: project)
+    issue2.labels << project.labels.find_by(title: 'bug')
+    issue2.labels << project.labels.find_by(title: 'enhancement')
+
+    issue3 = create(:issue, title: "Feature1", project: project)
+    issue3.labels << project.labels.find_by(title: 'feature')
+
+    project.team << [user, :master]
+    login_as(user)
+
+    visit namespace_project_issues_path(project.namespace, project)
+  end
+
+  context 'filter by label bug', js: true do
+    before do
+      page.find('.js-label-select').click
+      sleep 0.5
+      execute_script("$('.dropdown-menu-labels li:contains(\"bug\") a').click()")
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+    end
+
+    it 'should show issue "Bugfix1" and "Bugfix2" in issues list' do
+      expect(page).to have_content "Bugfix1"
+      expect(page).to have_content "Bugfix2"
+    end
+
+    it 'should not show "Feature1" in issues list' do
+      expect(page).not_to have_content "Feature1"
+    end
+
+    it 'should show label "bug" in filtered-labels' do
+      expect(find('.filtered-labels')).to have_content "bug"
+    end
+
+    it 'should not show label "feature" and "enhancement" in filtered-labels' do
+      expect(find('.filtered-labels')).not_to have_content "feature"
+      expect(find('.filtered-labels')).not_to have_content "enhancement"
+    end
+  end
+
+  context 'filter by label feature', js: true do
+    before do
+      page.find('.js-label-select').click
+      sleep 0.5
+      execute_script("$('.dropdown-menu-labels li:contains(\"feature\") a').click()")
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+    end
+
+    it 'should show issue "Feature1" in issues list' do
+      expect(page).to have_content "Feature1"
+    end
+
+    it 'should not show "Bugfix1" and "Bugfix2" in issues list' do
+      expect(page).not_to have_content "Bugfix2"
+      expect(page).not_to have_content "Bugfix1"
+    end
+
+    it 'should show label "feature" in filtered-labels' do
+      expect(find('.filtered-labels')).to have_content "feature"
+    end
+
+    it 'should not show label "bug" and "enhancement" in filtered-labels' do
+      expect(find('.filtered-labels')).not_to have_content "bug"
+      expect(find('.filtered-labels')).not_to have_content "enhancement"
+    end
+  end
+
+  context 'filter by label enhancement', js: true do
+    before do
+      page.find('.js-label-select').click
+      sleep 0.5
+      execute_script("$('.dropdown-menu-labels li:contains(\"enhancement\") a').click()")
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+    end
+
+    it 'should show issue "Bugfix2" in issues list' do
+      expect(page).to have_content "Bugfix2"
+    end
+
+    it 'should not show "Feature1" and "Bugfix1" in issues list' do
+      expect(page).not_to have_content "Feature1"
+      expect(page).not_to have_content "Bugfix1"
+    end
+
+    it 'should show label "enhancement" in filtered-labels' do
+      expect(find('.filtered-labels')).to have_content "enhancement"
+    end
+
+    it 'should not show label "feature" and "bug" in filtered-labels' do
+      expect(find('.filtered-labels')).not_to have_content "bug"
+      expect(find('.filtered-labels')).not_to have_content "feature"
+    end
+  end
+
+  context 'filter by label enhancement or feature', js: true do
+    before do
+      page.find('.js-label-select').click
+      sleep 0.5
+      execute_script("$('.dropdown-menu-labels li:contains(\"enhancement\") a').click()")
+      execute_script("$('.dropdown-menu-labels li:contains(\"feature\") a').click()")
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+    end
+
+    it 'should show issue "Bugfix2" or "Feature1" in issues list' do
+      expect(page).to have_content "Bugfix2"
+      expect(page).to have_content "Feature1"
+    end
+
+    it 'should not show "Bugfix1" in issues list' do
+      expect(page).not_to have_content "Bugfix1"
+    end
+
+    it 'should show label "enhancement" and "feature" in filtered-labels' do
+      expect(find('.filtered-labels')).to have_content "enhancement"
+      expect(find('.filtered-labels')).to have_content "feature"
+    end
+
+    it 'should not show label "bug" in filtered-labels' do
+      expect(find('.filtered-labels')).not_to have_content "bug"
+    end
+  end
+
+  context 'filter by label enhancement or bug in issues list', js: true do
+    before do
+      page.find('.js-label-select').click
+      sleep 0.5
+      execute_script("$('.dropdown-menu-labels li:contains(\"enhancement\") a').click()")
+      execute_script("$('.dropdown-menu-labels li:contains(\"bug\") a').click()")
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+    end
+
+    it 'should show issue "Bugfix2" or "Bugfix1" in issues list' do
+      expect(page).to have_content "Bugfix2"
+      expect(page).to have_content "Bugfix1"
+    end
+
+    it 'should not show "Feature1"' do
+      expect(page).not_to have_content "Feature1"
+    end
+
+    it 'should show label "bug" and "enhancement" in filtered-labels' do
+      expect(find('.filtered-labels')).to have_content "bug"
+      expect(find('.filtered-labels')).to have_content "enhancement"
+    end
+
+    it 'should not show label "feature" in filtered-labels' do
+      expect(find('.filtered-labels')).not_to have_content "feature"
+    end
+  end
+end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 69b22232f10723a999bf9fb595c526bbf752162d..192e3619375c8eb801f0b63e5d4d6e28f766b23b 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -84,14 +84,20 @@ describe 'Filter issues', feature: true do
 
     it 'should filter by any label' do
       find('.dropdown-menu-labels a', text: 'Any Label').click
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+
       page.within '.labels-filter' do
         expect(page).to have_content 'Any Label'
       end
-      expect(find('.js-label-select .dropdown-toggle-text')).to have_content('Label')
+      expect(find('.js-label-select .dropdown-toggle-text')).to have_content('Any Label')
     end
 
     it 'should filter by no label' do
       find('.dropdown-menu-labels a', text: 'No Label').click
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
+      sleep 2
+
       page.within '.labels-filter' do
         expect(page).to have_content 'No Label'
       end
@@ -121,6 +127,7 @@ describe 'Filter issues', feature: true do
       find('.js-label-select').click
 
       find('.dropdown-menu-labels .dropdown-content a', text: label.title).click
+      page.first('.labels-filter .dropdown-title .dropdown-menu-close-icon').click
 
       sleep 2
     end
diff --git a/spec/features/merge_requests/filter_by_milestone_spec.rb b/spec/features/merge_requests/filter_by_milestone_spec.rb
index c57ab5f3b0348ec1c4813e1e992ba61fdf88a6f3..e3ecd60a5f3e12ebedd772fc315d6d00f49d5ef0 100644
--- a/spec/features/merge_requests/filter_by_milestone_spec.rb
+++ b/spec/features/merge_requests/filter_by_milestone_spec.rb
@@ -2,8 +2,14 @@ require 'rails_helper'
 
 feature 'Merge Request filtering by Milestone', feature: true do
   let(:project)   { create(:project, :public) }
+  let!(:user)     { create(:user)}
   let(:milestone) { create(:milestone, project: project) }
 
+  before do
+    project.team << [user, :master]
+    login_as(user)
+  end
+
   scenario 'filters by no Milestone', js: true do
     create(:merge_request, :with_diffs, source_project: project)
     create(:merge_request, :simple, source_project: project, milestone: milestone)
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index b16480554622bf064284ce14688d2083a72332c3..bc607a29751d85639ab9c25f981ea8ccd672b465 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -62,6 +62,22 @@ describe IssuesFinder do
         expect(issues).to eq([issue2])
       end
 
+      it 'returns unique issues when filtering by multiple labels' do
+        label2 = create(:label, project: project2)
+
+        create(:label_link, label: label2, target: issue2)
+
+        params = {
+          scope:      'all',
+          label_name: [label.title, label2.title].join(','),
+          state:      'opened'
+        }
+
+        issues = IssuesFinder.new(user, params).execute
+
+        expect(issues).to eq([issue2])
+      end
+
       it 'should filter by no label name' do
         params = { scope: "all", label_name: Label::None.title, state: 'opened' }
         issues = IssuesFinder.new(user, params).execute