diff --git a/CHANGELOG b/CHANGELOG
index ca09d9c09f398b59caf5dafd82ff39ad740438e1..cc9fcf1992b133552d9cfa5d418b813c628013f8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -47,6 +47,7 @@ v 8.2.0
   - Fix trailing whitespace issue in merge request/issue title
   - Fix bug when milestone/label filter was empty for dashboard issues page
   - Add ability to create milestone in group projects from single form
+  - Prevent the last owner of a group from being able to delete themselves by 'adding' themselves as a master (James Lopez)
 
 v 8.1.4
   - Fix bug where manually merged branches in a MR would end up with an empty diff (Stan Hu)
diff --git a/app/controllers/groups/group_members_controller.rb b/app/controllers/groups/group_members_controller.rb
index b25957a06e2a82c192c11e5aa45343dbb2e28531..0e902c4bb4347958201b5430b7c6ece70dc068c5 100644
--- a/app/controllers/groups/group_members_controller.rb
+++ b/app/controllers/groups/group_members_controller.rb
@@ -3,8 +3,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
 
   # Authorize
   before_action :authorize_read_group!
-  before_action :authorize_admin_group!, except: [:index, :leave]
-  before_action :authorize_admin_group_member!, only: [:create, :resend_invite]
+  before_action :authorize_admin_group_member!, except: [:index, :leave]
 
   def index
     @project = @group.projects.find(params[:project_id]) if params[:project_id]
@@ -17,7 +16,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
     end
 
     @members = @members.order('access_level DESC').page(params[:page]).per(50)
-    @group_member = GroupMember.new
+
+    @group_member = @group.group_members.new
   end
 
   def create
@@ -27,24 +27,23 @@ class Groups::GroupMembersController < Groups::ApplicationController
   end
 
   def update
-    @member = @group.group_members.find(params[:id])
+    @group_member = @group.group_members.find(params[:id])
 
-    return render_403 unless can?(current_user, :update_group_member, @member)
+    return render_403 unless can?(current_user, :update_group_member, @group_member)
 
-    @member.update_attributes(member_params)
+    @group_member.update_attributes(member_params)
   end
 
   def destroy
     @group_member = @group.group_members.find(params[:id])
 
-    if can?(current_user, :destroy_group_member, @group_member)  # May fail if last owner.
-      @group_member.destroy
-      respond_to do |format|
-        format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
-        format.js { render nothing: true }
-      end
-    else
-      return render_403
+    return render_403 unless can?(current_user, :destroy_group_member, @group_member)
+
+    @group_member.destroy
+
+    respond_to do |format|
+      format.html { redirect_to group_group_members_path(@group), notice: 'User was successfully removed from group.' }
+      format.js { render nothing: true }
     end
   end
 
@@ -63,10 +62,11 @@ class Groups::GroupMembersController < Groups::ApplicationController
   end
 
   def leave
-    @group_member = @group.group_members.where(user_id: current_user.id).first
+    @group_member = @group.group_members.find_by(user_id: current_user)
 
     if can?(current_user, :destroy_group_member, @group_member)
       @group_member.destroy
+
       redirect_to(dashboard_groups_path, notice: "You left #{group.name} group.")
     else
       if @group.last_owner?(current_user)
diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb
index 9de5269cd2520abaea1b308e694dfd3999754f9d..07eb94e4f48dd9967b7ac435f73702f56e661c30 100644
--- a/app/controllers/projects/project_members_controller.rb
+++ b/app/controllers/projects/project_members_controller.rb
@@ -1,6 +1,6 @@
 class Projects::ProjectMembersController < Projects::ApplicationController
   # Authorize
-  before_action :authorize_admin_project!, except: :leave
+  before_action :authorize_admin_project_member!, except: :leave
 
   def index
     @project_members = @project.project_members
@@ -29,10 +29,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController
     @project_member = @project.project_members.new
   end
 
-  def new
-    @project_member = @project.project_members.new
-  end
-
   def create
     @project.team.add_users(params[:user_ids].split(','), params[:access_level], current_user)
 
@@ -41,11 +37,17 @@ class Projects::ProjectMembersController < Projects::ApplicationController
 
   def update
     @project_member = @project.project_members.find(params[:id])
+
+    return render_403 unless can?(current_user, :update_project_member, @project_member)
+
     @project_member.update_attributes(member_params)
   end
 
   def destroy
     @project_member = @project.project_members.find(params[:id])
+
+    return render_403 unless can?(current_user, :destroy_project_member, @project_member)
+
     @project_member.destroy
 
     respond_to do |format|
@@ -71,16 +73,22 @@ class Projects::ProjectMembersController < Projects::ApplicationController
   end
 
   def leave
-    if @project.namespace == current_user.namespace
-      message = 'You can not leave your own project. Transfer or delete the project.'
-      return redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
-    end
+    @project_member = @project.project_members.find_by(user_id: current_user)
 
-    @project.project_members.find_by(user_id: current_user).destroy
+    if can?(current_user, :destroy_project_member, @project_member)
+      @project_member.destroy
 
-    respond_to do |format|
-      format.html { redirect_to dashboard_projects_path }
-      format.js { render nothing: true }
+      respond_to do |format|
+        format.html { redirect_to dashboard_projects_path, notice: "You left the project." }
+        format.js { render nothing: true }
+      end
+    else
+      if current_user == @project.owner
+        message = 'You can not leave your own project. Transfer or delete the project.'
+        redirect_back_or_default(default: { action: 'index' }, options: { alert: message })
+      else
+        render_403
+      end
     end
   end
 
diff --git a/app/models/ability.rb b/app/models/ability.rb
index d01b3ae6f050a88b91e996212cab05546811c50d..500af08d20948dd441d2d1fc2212a64d0b97b637 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -15,6 +15,7 @@ class Ability
       when "Group" then group_abilities(user, subject)
       when "Namespace" then namespace_abilities(user, subject)
       when "GroupMember" then group_member_abilities(user, subject)
+      when "ProjectMember" then project_member_abilities(user, subject)
       else []
       end.concat(global_abilities(user))
     end
@@ -231,19 +232,19 @@ class Ability
 
       # Only group masters and group owners can create new projects in group
       if group.has_master?(user) || group.has_owner?(user) || user.admin?
-        rules.push(*[
+        rules += [
           :create_projects,
           :admin_milestones
-        ])
+        ]
       end
 
       # Only group owner and administrators can admin group
       if group.has_owner?(user) || user.admin?
-        rules.push(*[
+        rules += [
           :admin_group,
           :admin_namespace,
           :admin_group_member
-        ])
+        ]
       end
 
       rules.flatten
@@ -254,16 +255,15 @@ class Ability
 
       # Only namespace owner and administrators can admin it
       if namespace.owner == user || user.admin?
-        rules.push(*[
+        rules += [
           :create_projects,
           :admin_namespace
-        ])
+        ]
       end
 
       rules.flatten
     end
 
-
     [:issue, :merge_request].each do |name|
       define_method "#{name}_abilities" do |user, subject|
         rules = []
@@ -304,15 +304,39 @@ class Ability
       rules = []
       target_user = subject.user
       group = subject.group
-      can_manage = group_abilities(user, group).include?(:admin_group_member)
 
-      if can_manage && (user != target_user)
-        rules << :update_group_member
-        rules << :destroy_group_member
+      unless group.last_owner?(target_user)
+        can_manage = group_abilities(user, group).include?(:admin_group_member)
+
+        if can_manage && user != target_user
+          rules << :update_group_member
+          rules << :destroy_group_member
+        end
+
+        if user == target_user
+          rules << :destroy_group_member
+        end
       end
 
-      if !group.last_owner?(user) && (can_manage || (user == target_user))
-        rules << :destroy_group_member
+      rules
+    end
+
+    def project_member_abilities(user, subject)
+      rules = []
+      target_user = subject.user
+      project = subject.project
+
+      unless target_user == project.owner
+        can_manage = project_abilities(user, project).include?(:admin_project_member)
+
+        if can_manage && user != target_user
+          rules << :update_project_member
+          rules << :destroy_project_member
+        end
+
+        if user == target_user
+          rules << :destroy_project_member
+        end
       end
 
       rules
@@ -320,10 +344,10 @@ class Ability
 
     def abilities
       @abilities ||= begin
-                       abilities = Six.new
-                       abilities << self
-                       abilities
-                     end
+        abilities = Six.new
+        abilities << self
+        abilities
+      end
     end
 
     private
diff --git a/app/models/group.rb b/app/models/group.rb
index 793a3b5ef2e4a92faa8512510d5bf90b898dff34..2c9e75496b9c6353de48279b27be17c748bf5a02 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -20,8 +20,9 @@ require 'file_size_validator'
 class Group < Namespace
   include Gitlab::ConfigHelper
   include Referable
-
+  
   has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
+  alias_method :members, :group_members
   has_many :users, through: :group_members
 
   validate :avatar_type, if: ->(user) { user.avatar.present? && user.avatar_changed? }
@@ -110,10 +111,6 @@ class Group < Namespace
     has_owner?(user) && owners.size == 1
   end
 
-  def members
-    group_members
-  end
-
   def avatar_type
     unless self.avatar.image?
       self.errors.add :avatar, "only images allowed"
diff --git a/app/models/member.rb b/app/models/member.rb
index cae8caa23fb2770299ee935b82f48edecd22f39b..28aee2e379963224b4459c4b5251d10464528d63 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -30,13 +30,22 @@ class Member < ActiveRecord::Base
 
   validates :user, presence: true, unless: :invite?
   validates :source, presence: true
-  validates :user_id, uniqueness: { scope: [:source_type, :source_id], 
+  validates :user_id, uniqueness: { scope: [:source_type, :source_id],
                                     message: "already exists in source",
                                     allow_nil: true }
   validates :access_level, inclusion: { in: Gitlab::Access.all_values }, presence: true
-  validates :invite_email,  presence: { if: :invite? }, 
-                            email: { strict_mode: true, allow_nil: true }, 
-                            uniqueness: { scope: [:source_type, :source_id], allow_nil: true }
+  validates :invite_email,
+    presence: {
+      if: :invite?
+    },
+    email: {
+      strict_mode: true,
+      allow_nil: true
+    },
+    uniqueness: {
+      scope: [:source_type, :source_id],
+      allow_nil: true
+    }
 
   scope :invite, -> { where(user_id: nil) }
   scope :non_invite, -> { where("user_id IS NOT NULL") }
@@ -73,7 +82,7 @@ class Member < ActiveRecord::Base
 
     def add_user(members, user_id, access_level, current_user = nil)
       user = user_for_id(user_id)
-      
+
       # `user` can be either a User object or an email to be invited
       if user.is_a?(User)
         member = members.find_or_initialize_by(user_id: user.id)
@@ -82,10 +91,21 @@ class Member < ActiveRecord::Base
         member.invite_email = user
       end
 
-      member.created_by ||= current_user
-      member.access_level = access_level
+      if can_update_member?(current_user, member)
+        member.created_by ||= current_user
+        member.access_level = access_level
+
+        member.save
+      end
+    end
+
+    private
 
-      member.save
+    def can_update_member?(current_user, member)
+      # There is no current user for bulk actions, in which case anything is allowed
+      !current_user ||
+        current_user.can?(:update_group_member, member) ||
+        current_user.can?(:update_project_member, member)
     end
   end
 
@@ -95,7 +115,7 @@ class Member < ActiveRecord::Base
 
   def accept_invite!(new_user)
     return false unless invite?
-    
+
     self.invite_token = nil
     self.invite_accepted_at = Time.now.utc
 
diff --git a/app/models/project.rb b/app/models/project.rb
index 9ea0d15497acb25833a9d56c679e5ea1ce9e1f09..a099a67cf639298fe54366803338c8227e9206c2 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -42,7 +42,7 @@ class Project < ActiveRecord::Base
   include Sortable
   include AfterCommitQueue
   include CaseSensitivity
-
+  
   extend Gitlab::ConfigHelper
   extend Enumerize
 
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index 3c19381321aec37e36924f7c34635726ea265fde..be94b1abc11fdf2de51de541309f1bd224b66b82 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -1,6 +1,5 @@
 - user = member.user
 - return unless user || member.invite?
-- show_roles = true if show_roles.nil?
 
 %li{class: "#{dom_class(member)} js-toggle-container", id: dom_id(member)}
   %span{class: ("list-item-name" if show_controls)}
@@ -25,11 +24,11 @@
           = link_to member.created_by.name, user_path(member.created_by)
         = time_ago_with_tooltip(member.created_at)
 
-      - if show_controls && can?(current_user, :admin_group_member, member)
+      - if show_controls && can?(current_user, :admin_group_member, @group)
         = link_to resend_invite_group_group_member_path(@group, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do
           Resend invite
 
-  - if show_roles
+  - if should_user_see_group_roles?(current_user, @group)
     %span.pull-right
       %strong= member.human_access
       - if show_controls
@@ -37,6 +36,7 @@
           = button_tag class: "btn-xs btn js-toggle-button",
                        title: 'Edit access level', type: 'button' do
             %i.fa.fa-pencil-square-o
+
         - if can?(current_user, :destroy_group_member, member)
           &nbsp;
           - if current_user == user
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 15d289471c9a743ac532d4b6b86588d98577971c..d4ad33a8bf144a68373ed24747447ac5219a3f30 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,8 +1,6 @@
 - page_title "Members"
 - header_title group_title(@group, "Members", group_group_members_path(@group))
-- show_roles = should_user_see_group_roles?(current_user, @group)
-
-- if show_roles
+- if should_user_see_group_roles?(current_user, @group)
   %p.light
     Members of group have access to all group projects.
     Read more about permissions
@@ -32,7 +30,7 @@
       (#{@members.total_count})
   %ul.well-list
     - @members.each do |member|
-      = render 'groups/group_members/group_member', member: member, show_roles: show_roles, show_controls: true
+      = render 'groups/group_members/group_member', member: member, show_controls: true
 
 = paginate @members, theme: 'gitlab'
 
diff --git a/app/views/projects/project_members/_project_member.html.haml b/app/views/projects/project_members/_project_member.html.haml
index 76c46d1d8067a7fe7dc855fa09a342c40260dbc6..f07cd97e63d45316913e2d4a981da4ba648dc367 100644
--- a/app/views/projects/project_members/_project_member.html.haml
+++ b/app/views/projects/project_members/_project_member.html.haml
@@ -24,18 +24,19 @@
           = link_to member.created_by.name, user_path(member.created_by)
         = time_ago_with_tooltip(member.created_at)
 
-      - if current_user_can_admin_project
+      - if can?(current_user, :admin_project_member, @project)
         = link_to resend_invite_namespace_project_project_member_path(@project.namespace, @project, member), method: :post, class: "btn-xs btn", title: 'Resend invite' do
           Resend invite
 
-  - if current_user_can_admin_project
-    - unless @project.personal? && user == current_user
-      .pull-right
-        %strong= member.human_access
+  - if can?(current_user, :admin_project_member, @project)
+    .pull-right
+      %strong= member.human_access
+      - if can?(current_user, :update_project_member, member)
         = button_tag class: "btn-xs btn js-toggle-button",
                      title: 'Edit access level', type: 'button' do
           %i.fa.fa-pencil-square-o
 
+      - if can?(current_user, :destroy_project_member, member)
         &nbsp;
         - if current_user == user
           = link_to leave_namespace_project_project_members_path(@project.namespace, @project), data: { confirm: leave_project_message(@project) }, method: :delete, class: "btn-xs btn btn-remove", title: 'Leave project' do
diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml
index 615c425e59ae2967a6ba90f5d7ff6ad8bd83103d..b807fb2cc9dffa65257ec981a93d968436762175 100644
--- a/app/views/projects/project_members/_team.html.haml
+++ b/app/views/projects/project_members/_team.html.haml
@@ -1,5 +1,3 @@
-- can_admin_project = can?(current_user, :admin_project, @project)
-
 .panel.panel-default.prepend-top-20
   .panel-heading
     %strong #{@project.name}
@@ -8,4 +6,4 @@
       (#{members.count})
   %ul.well-list
     - members.each do |project_member|
-      = render 'project_member', member: project_member, current_user_can_admin_project: can_admin_project
+      = render 'project_member', member: project_member
diff --git a/app/views/projects/project_members/update.js.haml b/app/views/projects/project_members/update.js.haml
index 811b1858821c93518116a449322dc0b161954f77..2fb3a41d541051ba1fa06df53f611abb0e60b4c5 100644
--- a/app/views/projects/project_members/update.js.haml
+++ b/app/views/projects/project_members/update.js.haml
@@ -1,3 +1,2 @@
-- can_admin_project = can?(current_user, :admin_project, @project)
 :plain
-  $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render("project_member", member: @project_member, current_user_can_admin_project: can_admin_project))}');
+  $("##{dom_id(@project_member)}").replaceWith('#{escape_javascript(render("project_member", member: @project_member))}');
diff --git a/features/groups.feature b/features/groups.feature
index 615eff6a330607aa719bc70e6ee6d7e977572b57..abf3769a84446c7355cf924a30abe0b2549892a2 100644
--- a/features/groups.feature
+++ b/features/groups.feature
@@ -59,6 +59,14 @@ Feature: Groups
     When I select "Mike" as "Reporter"
     Then I should see "Mike" in team list as "Reporter"
 
+  @javascript
+  Scenario: Ignore add user to group when is already Owner
+    Given gitlab user "Mike"
+    When I visit group "Owned" members page
+    And I click link "Add members"
+    When I select "Mike" as "Reporter"
+    Then I should see "Mike" in team list as "Owner"
+
   @javascript
   Scenario: Invite user to group
     When I visit group "Owned" members page
diff --git a/features/steps/groups.rb b/features/steps/groups.rb
index a8fba2406ae0d0cd8ce54fcc2304d836498eaf4f..9c0313537b12db5573d86d1e956494dfc34e543c 100644
--- a/features/steps/groups.rb
+++ b/features/steps/groups.rb
@@ -48,6 +48,17 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
     click_button "Add users to group"
   end
 
+  step 'I select "Mike" as "Master"' do
+    user = User.find_by(name: "Mike")
+
+    page.within ".users-group-form" do
+      select2(user.id, from: "#user_ids", multiple: true)
+      select "Master", from: "access_level"
+    end
+
+    click_button "Add users to group"
+  end
+
   step 'I should see "Mike" in team list as "Reporter"' do
     page.within '.well-list' do
       expect(page).to have_content('Mike')
@@ -55,6 +66,13 @@ class Spinach::Features::Groups < Spinach::FeatureSteps
     end
   end
 
+  step 'I should see "Mike" in team list as "Owner"' do
+    page.within '.well-list' do
+      expect(page).to have_content('Mike')
+      expect(page).to have_content('Owner')
+    end
+  end
+
   step 'I select "sjobs@apple.com" as "Reporter"' do
     page.within ".users-group-form" do
       select2("sjobs@apple.com", from: "#user_ids", multiple: true)