diff --git a/models/branches.go b/models/branches.go
index 1932e06db3..b6398f5694 100644
--- a/models/branches.go
+++ b/models/branches.go
@@ -93,8 +93,8 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
 	return in
 }
 
-// CanUserMerge returns if some user could merge a pull request to this protected branch
-func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
+// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
+func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64) bool {
 	if !protectBranch.EnableMergeWhitelist {
 		return true
 	}
@@ -348,27 +348,6 @@ func (repo *Repository) IsProtectedBranchForPush(branchName string, doer *User)
 	return false, nil
 }
 
-// IsProtectedBranchForMerging checks if branch is protected for merging
-func (repo *Repository) IsProtectedBranchForMerging(pr *PullRequest, branchName string, doer *User) (bool, error) {
-	if doer == nil {
-		return true, nil
-	}
-
-	protectedBranch := &ProtectedBranch{
-		RepoID:     repo.ID,
-		BranchName: branchName,
-	}
-
-	has, err := x.Get(protectedBranch)
-	if err != nil {
-		return true, err
-	} else if has {
-		return !protectedBranch.CanUserMerge(doer.ID) || !protectedBranch.HasEnoughApprovals(pr) || protectedBranch.MergeBlockedByRejectedReview(pr), nil
-	}
-
-	return false, nil
-}
-
 // updateApprovalWhitelist checks whether the user whitelist changed and returns a whitelist with
 // the users from newWhitelist which have explicit read or write access to the repo.
 func updateApprovalWhitelist(repo *Repository, currentWhitelist, newWhitelist []int64) (whitelist []int64, err error) {
diff --git a/models/pull.go b/models/pull.go
index e2a35c5920..bf2527679f 100644
--- a/models/pull.go
+++ b/models/pull.go
@@ -479,31 +479,6 @@ const (
 	MergeStyleSquash MergeStyle = "squash"
 )
 
-// CheckUserAllowedToMerge checks whether the user is allowed to merge
-func (pr *PullRequest) CheckUserAllowedToMerge(doer *User) (err error) {
-	if doer == nil {
-		return ErrNotAllowedToMerge{
-			"Not signed in",
-		}
-	}
-
-	if pr.BaseRepo == nil {
-		if err = pr.GetBaseRepo(); err != nil {
-			return fmt.Errorf("GetBaseRepo: %v", err)
-		}
-	}
-
-	if protected, err := pr.BaseRepo.IsProtectedBranchForMerging(pr, pr.BaseBranch, doer); err != nil {
-		return fmt.Errorf("IsProtectedBranch: %v", err)
-	} else if protected {
-		return ErrNotAllowedToMerge{
-			"The branch is protected",
-		}
-	}
-
-	return nil
-}
-
 // SetMerged sets a pull request to merged and closes the corresponding issue
 func (pr *PullRequest) SetMerged() (err error) {
 	if pr.HasMerged {
diff --git a/models/repo_permission.go b/models/repo_permission.go
index 79d7dd012b..374c6f8d56 100644
--- a/models/repo_permission.go
+++ b/models/repo_permission.go
@@ -271,7 +271,7 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
 	return
 }
 
-// IsUserRepoAdmin return ture if user has admin right of a repo
+// IsUserRepoAdmin return true if user has admin right of a repo
 func IsUserRepoAdmin(repo *Repository, user *User) (bool, error) {
 	return isUserRepoAdmin(x, repo, user)
 }
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 28615ebbc4..0086419b65 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -448,6 +448,7 @@ type MergePullRequestForm struct {
 	Do                string `binding:"Required;In(merge,rebase,rebase-merge,squash)"`
 	MergeTitleField   string
 	MergeMessageField string
+	ForceMerge        *bool `json:"force_merge,omitempty"`
 }
 
 // Validate validates the fields
diff --git a/modules/convert/convert.go b/modules/convert/convert.go
index 4479653174..a69b09a2b7 100644
--- a/modules/convert/convert.go
+++ b/modules/convert/convert.go
@@ -51,7 +51,7 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
 		EnableStatusCheck:   bp.EnableStatusCheck,
 		StatusCheckContexts: bp.StatusCheckContexts,
 		UserCanPush:         bp.CanUserPush(user.ID),
-		UserCanMerge:        bp.CanUserMerge(user.ID),
+		UserCanMerge:        bp.IsUserMergeWhitelisted(user.ID),
 	}
 }
 
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index a00df07d93..4dc0b92234 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1062,7 +1062,8 @@ pulls.cannot_auto_merge_helper = Merge manually to resolve the conflicts.
 pulls.no_merge_desc = This pull request cannot be merged because all repository merge options are disabled.
 pulls.no_merge_helper = Enable merge options in the repository settings or merge the pull request manually.
 pulls.no_merge_wip = This pull request can not be merged because it is marked as being a work in progress.
-pulls.no_merge_status_check = This pull request cannot be merged because not all required status checkes are successful.
+pulls.no_merge_not_ready = This pull request is not ready to be merged, check review status and status checks.
+pulls.no_merge_access = You are not authorized to merge this pull request.
 pulls.merge_pull_request = Merge Pull Request
 pulls.rebase_merge_pull_request = Rebase and Merge
 pulls.rebase_merge_commit_pull_request = Rebase and Merge (--no-ff)
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 8e6677116d..6b643371e5 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -600,20 +600,43 @@ func MergePullRequest(ctx *context.APIContext, form auth.MergePullRequestForm) {
 		return
 	}
 
+	perm, err := models.GetUserRepoPermission(ctx.Repo.Repository, ctx.User)
+	if err != nil {
+		ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err)
+		return
+	}
+
+	allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, perm, ctx.User)
+	if err != nil {
+		ctx.Error(http.StatusInternalServerError, "IsUSerAllowedToMerge", err)
+		return
+	}
+	if !allowedMerge {
+		ctx.Error(http.StatusMethodNotAllowed, "Merge", "User not allowed to merge PR")
+		return
+	}
+
 	if !pr.CanAutoMerge() || pr.HasMerged || pr.IsWorkInProgress() {
 		ctx.Status(http.StatusMethodNotAllowed)
 		return
 	}
 
-	isPass, err := pull_service.IsPullCommitStatusPass(pr)
-	if err != nil {
-		ctx.Error(http.StatusInternalServerError, "IsPullCommitStatusPass", err)
-		return
-	}
-
-	if !isPass && !ctx.IsUserRepoAdmin() {
-		ctx.Status(http.StatusMethodNotAllowed)
-		return
+	if err := pull_service.CheckPRReadyToMerge(pr); err != nil {
+		if !models.IsErrNotAllowedToMerge(err) {
+			ctx.Error(http.StatusInternalServerError, "CheckPRReadyToMerge", err)
+			return
+		}
+		if form.ForceMerge != nil && *form.ForceMerge {
+			if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
+				ctx.Error(http.StatusInternalServerError, "IsUserRepoAdmin", err)
+				return
+			} else if !isRepoAdmin {
+				ctx.Error(http.StatusMethodNotAllowed, "Merge", "Only repository admin can merge if not all checks are ok (force merge)")
+			}
+		} else {
+			ctx.Error(http.StatusMethodNotAllowed, "PR is not ready to be merged", err)
+			return
+		}
 	}
 
 	if len(form.Do) == 0 {
diff --git a/routers/private/hook.go b/routers/private/hook.go
index c1e283f357..b4626fddf4 100644
--- a/routers/private/hook.go
+++ b/routers/private/hook.go
@@ -17,6 +17,7 @@ import (
 	"code.gitea.io/gitea/modules/private"
 	"code.gitea.io/gitea/modules/repofiles"
 	"code.gitea.io/gitea/modules/util"
+	pull_service "code.gitea.io/gitea/services/pull"
 
 	"gitea.com/macaron/macaron"
 )
@@ -98,6 +99,7 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
 				canPush = protectBranch.CanUserPush(opts.UserID)
 			}
 			if !canPush && opts.ProtectedBranchID > 0 {
+				// Manual merge
 				pr, err := models.GetPullRequestByID(opts.ProtectedBranchID)
 				if err != nil {
 					log.Error("Unable to get PullRequest %d Error: %v", opts.ProtectedBranchID, err)
@@ -106,24 +108,55 @@ func HookPreReceive(ctx *macaron.Context, opts private.HookOptions) {
 					})
 					return
 				}
-				if !protectBranch.HasEnoughApprovals(pr) {
-					log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d does not have enough approvals", opts.UserID, branchName, repo, pr.Index)
-					ctx.JSON(http.StatusForbidden, map[string]interface{}{
-						"err": fmt.Sprintf("protected branch %s can not be pushed to and pr #%d does not have enough approvals", branchName, opts.ProtectedBranchID),
+				user, err := models.GetUserByID(opts.UserID)
+				if err != nil {
+					log.Error("Unable to get User id %d Error: %v", opts.UserID, err)
+					ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
+						"err": fmt.Sprintf("Unable to get User id %d Error: %v", opts.UserID, err),
 					})
 					return
 				}
-				if protectBranch.MergeBlockedByRejectedReview(pr) {
-					log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v and pr #%d has requested changes", opts.UserID, branchName, repo, pr.Index)
-					ctx.JSON(http.StatusForbidden, map[string]interface{}{
-						"err": fmt.Sprintf("protected branch %s can not be pushed to and pr #%d has requested changes", branchName, opts.ProtectedBranchID),
+				perm, err := models.GetUserRepoPermission(repo, user)
+				if err != nil {
+					log.Error("Unable to get Repo permission of repo %s/%s of User %s", repo.OwnerName, repo.Name, user.Name, err)
+					ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
+						"err": fmt.Sprintf("Unable to get Repo permission of repo %s/%s of User %s: %v", repo.OwnerName, repo.Name, user.Name, err),
 					})
 					return
 				}
+				allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, perm, user)
+				if err != nil {
+					log.Error("Error calculating if allowed to merge: %v", err)
+					ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
+						"err": fmt.Sprintf("Error calculating if allowed to merge: %v", err),
+					})
+					return
+				}
+				if !allowedMerge {
+					log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v and is not allowed to merge pr #%d", opts.UserID, branchName, repo, pr.Index)
+					ctx.JSON(http.StatusForbidden, map[string]interface{}{
+						"err": fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
+					})
+					return
+				}
+				// Manual merge only allowed if PR is ready (even if admin)
+				if err := pull_service.CheckPRReadyToMerge(pr); err != nil {
+					if models.IsErrNotAllowedToMerge(err) {
+						log.Warn("Forbidden: User %d is not allowed push to protected branch %s in %-v and pr #%d is not ready to be merged: %s", opts.UserID, branchName, repo, pr.Index, err.Error())
+						ctx.JSON(http.StatusForbidden, map[string]interface{}{
+							"err": fmt.Sprintf("Not allowed to push to protected branch %s and pr #%d is not ready to be merged: %s", branchName, opts.ProtectedBranchID, err.Error()),
+						})
+						return
+					}
+					log.Error("Unable to check if mergable: protected branch %s in %-v and pr #%d. Error: %v", opts.UserID, branchName, repo, pr.Index, err)
+					ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
+						"err": fmt.Sprintf("Unable to get status of pull request %d. Error: %v", opts.ProtectedBranchID, err),
+					})
+				}
 			} else if !canPush {
-				log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", opts.UserID, branchName, repo)
+				log.Warn("Forbidden: User %d is not allowed to push to protected branch: %s in %-v", opts.UserID, branchName, repo)
 				ctx.JSON(http.StatusForbidden, map[string]interface{}{
-					"err": fmt.Sprintf("protected branch %s can not be pushed to", branchName),
+					"err": fmt.Sprintf("Not allowed to push to protected branch %s", branchName),
 				})
 				return
 			}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 0a78e06b41..ce3eb5bd2c 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -903,6 +903,7 @@ func ViewIssue(ctx *context.Context) {
 		pull := issue.PullRequest
 		pull.Issue = issue
 		canDelete := false
+		ctx.Data["AllowMerge"] = false
 
 		if ctx.IsSigned {
 			if err := pull.GetHeadRepo(); err != nil {
@@ -923,6 +924,20 @@ func ViewIssue(ctx *context.Context) {
 					}
 				}
 			}
+
+			if err := pull.GetBaseRepo(); err != nil {
+				log.Error("GetBaseRepo: %v", err)
+			}
+			perm, err := models.GetUserRepoPermission(pull.BaseRepo, ctx.User)
+			if err != nil {
+				ctx.ServerError("GetUserRepoPermission", err)
+				return
+			}
+			ctx.Data["AllowMerge"], err = pull_service.IsUserAllowedToMerge(pull, perm, ctx.User)
+			if err != nil {
+				ctx.ServerError("IsUserAllowedToMerge", err)
+				return
+			}
 		}
 
 		prUnit, err := repo.GetUnit(models.UnitTypePullRequests)
@@ -932,15 +947,6 @@ func ViewIssue(ctx *context.Context) {
 		}
 		prConfig := prUnit.PullRequestsConfig()
 
-		ctx.Data["AllowMerge"] = ctx.Repo.CanWrite(models.UnitTypeCode)
-		if err := pull.CheckUserAllowedToMerge(ctx.User); err != nil {
-			if !models.IsErrNotAllowedToMerge(err) {
-				ctx.ServerError("CheckUserAllowedToMerge", err)
-				return
-			}
-			ctx.Data["AllowMerge"] = false
-		}
-
 		// Check correct values and select default
 		if ms, ok := ctx.Data["MergeStyle"].(models.MergeStyle); !ok ||
 			!prConfig.IsMergeStyleAllowed(ms) {
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 93e98e0c33..901ab48856 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -600,6 +600,16 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
 
 	pr := issue.PullRequest
 
+	allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.Repo.Permission, ctx.User)
+	if err != nil {
+		ctx.ServerError("IsUserAllowedToMerge", err)
+		return
+	}
+	if !allowedMerge {
+		ctx.NotFound("MergePullRequest", nil)
+		return
+	}
+
 	if !pr.CanAutoMerge() || pr.HasMerged {
 		ctx.NotFound("MergePullRequest", nil)
 		return
@@ -611,15 +621,19 @@ func MergePullRequest(ctx *context.Context, form auth.MergePullRequestForm) {
 		return
 	}
 
-	isPass, err := pull_service.IsPullCommitStatusPass(pr)
-	if err != nil {
-		ctx.ServerError("IsPullCommitStatusPass", err)
-		return
-	}
-	if !isPass && !ctx.IsUserRepoAdmin() {
-		ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_status_check"))
-		ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
-		return
+	if err := pull_service.CheckPRReadyToMerge(pr); err != nil {
+		if !models.IsErrNotAllowedToMerge(err) {
+			ctx.ServerError("Merge PR status", err)
+			return
+		}
+		if isRepoAdmin, err := models.IsUserRepoAdmin(pr.BaseRepo, ctx.User); err != nil {
+			ctx.ServerError("IsUserRepoAdmin", err)
+			return
+		} else if !isRepoAdmin {
+			ctx.Flash.Error(ctx.Tr("repo.pulls.no_merge_not_ready"))
+			ctx.Redirect(ctx.Repo.RepoLink + "/pulls/" + com.ToStr(pr.Index))
+			return
+		}
 	}
 
 	if ctx.HasError() {
diff --git a/services/pull/merge.go b/services/pull/merge.go
index 7aec7cef3e..e825c3fdd1 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -30,6 +30,7 @@ import (
 )
 
 // Merge merges pull request to base repository.
+// Caller should check PR is ready to be merged (review and status checks)
 // FIXME: add repoWorkingPull make sure two merges does not happen at same time.
 func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repository, mergeStyle models.MergeStyle, message string) (err error) {
 	binVersion, err := git.BinVersion()
@@ -53,11 +54,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 	}
 	prConfig := prUnit.PullRequestsConfig()
 
-	if err := pr.CheckUserAllowedToMerge(doer); err != nil {
-		log.Error("CheckUserAllowedToMerge(%v): %v", doer, err)
-		return fmt.Errorf("CheckUserAllowedToMerge: %v", err)
-	}
-
 	// Check if merge style is correct and allowed
 	if !prConfig.IsMergeStyleAllowed(mergeStyle) {
 		return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: mergeStyle}
@@ -473,3 +469,64 @@ func getDiffTree(repoPath, baseBranch, headBranch string) (string, error) {
 
 	return out.String(), nil
 }
+
+// IsUserAllowedToMerge check if user is allowed to merge PR with given permissions and branch protections
+func IsUserAllowedToMerge(pr *models.PullRequest, p models.Permission, user *models.User) (bool, error) {
+	if p.IsAdmin() {
+		return true, nil
+	}
+	if !p.CanWrite(models.UnitTypeCode) {
+		return false, nil
+	}
+
+	err := pr.LoadProtectedBranch()
+	if err != nil {
+		return false, err
+	}
+
+	if pr.ProtectedBranch == nil || pr.ProtectedBranch.IsUserMergeWhitelisted(user.ID) {
+		return true, nil
+	}
+
+	return false, nil
+}
+
+// CheckPRReadyToMerge checks whether the PR is ready to be merged (reviews and status checks)
+func CheckPRReadyToMerge(pr *models.PullRequest) (err error) {
+	if pr.BaseRepo == nil {
+		if err = pr.GetBaseRepo(); err != nil {
+			return fmt.Errorf("GetBaseRepo: %v", err)
+		}
+	}
+	if pr.ProtectedBranch == nil {
+		if err = pr.LoadProtectedBranch(); err != nil {
+			return fmt.Errorf("LoadProtectedBranch: %v", err)
+		}
+		if pr.ProtectedBranch == nil {
+			return nil
+		}
+	}
+
+	isPass, err := IsPullCommitStatusPass(pr)
+	if err != nil {
+		return err
+	}
+	if !isPass {
+		return models.ErrNotAllowedToMerge{
+			Reason: "Not all required status checks successful",
+		}
+	}
+
+	if enoughApprovals := pr.ProtectedBranch.HasEnoughApprovals(pr); !enoughApprovals {
+		return models.ErrNotAllowedToMerge{
+			Reason: "Does not have enough approvals",
+		}
+	}
+	if rejected := pr.ProtectedBranch.MergeBlockedByRejectedReview(pr); rejected {
+		return models.ErrNotAllowedToMerge{
+			Reason: "There are requested changes",
+		}
+	}
+
+	return nil
+}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl
index 9dedc7dad7..7073312b1f 100644
--- a/templates/repo/issue/view_content/pull.tmpl
+++ b/templates/repo/issue/view_content/pull.tmpl
@@ -101,35 +101,31 @@
 					<span class="octicon octicon-x"></span>
 					{{$.i18n.Tr "repo.pulls.cannot_merge_work_in_progress" .WorkInProgressPrefix | Str2html}}
 				</div>
-			{{else if .IsBlockedByApprovals}}
-				<div class="item text red">
-					<span class="octicon octicon-x"></span>
-				{{$.i18n.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .Issue.PullRequest.ProtectedBranch.RequiredApprovals}}
-				</div>
-			{{else if .IsBlockedByRejection}}
-				<div class="item text red">
-					<span class="octicon octicon-x"></span>
-				{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}}
-				</div>
 			{{else if .Issue.PullRequest.IsChecking}}
 				<div class="item text yellow">
 					<span class="octicon octicon-sync"></span>
 					{{$.i18n.Tr "repo.pulls.is_checking"}}
 				</div>
-			{{else if and (not .Issue.PullRequest.CanAutoMerge) .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
-				<div class="item text red">
-					<span class="octicon octicon-x"></span>
-					{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
-				</div>
 			{{else if .Issue.PullRequest.CanAutoMerge}}
-				{{if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
-				<div class="item text red">
-					<span class="octicon octicon-x"></span>
-					{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
-				</div>
+				{{if .IsBlockedByApprovals}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+					{{$.i18n.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .Issue.PullRequest.ProtectedBranch.RequiredApprovals}}
+					</div>
+				{{else if .IsBlockedByRejection}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+					{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}}
+					</div>
+				{{else if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+						{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
+					</div>
 				{{end}}
-				{{if or $.IsRepoAdmin (not .EnableStatusCheck) .IsRequiredStatusCheckSuccess}}
-					{{if and $.IsRepoAdmin .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
+				{{$notAllOk := or .IsBlockedByApprovals .IsBlockedByRejection (and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess))}}	
+				{{if or $.IsRepoAdmin (not $notAllOk)}}
+					{{if $notAllOk}}
 						<div class="item text yellow">
 							<span class="octicon octicon-primitive-dot"></span>
 							{{$.i18n.Tr "repo.pulls.required_status_check_administrator"}}
@@ -216,7 +212,7 @@
 								</form>
 							</div>
 							{{end}}
-							<div class="ui green buttons merge-button">
+							<div class="ui {{if $notAllOk}}red{{else}}green{{end}} buttons merge-button">
 								<button class="ui button" data-do="{{.MergeStyle}}">
 									<span class="octicon octicon-git-merge"></span>
 									<span class="button-text">
@@ -262,17 +258,40 @@
 								{{$.i18n.Tr "repo.pulls.no_merge_helper"}}
 							</div>
 						{{end}}
+					{{else}}
+						<div class="item text grey">
+							<span class="octicon octicon-info"></span>
+							{{$.i18n.Tr "repo.pulls.no_merge_access"}}
+						</div>
 					{{end}}
 				{{end}}
 			{{else}}
-				<div class="item text red">
-					<span class="octicon octicon-x"></span>
-					{{$.i18n.Tr "repo.pulls.cannot_auto_merge_desc"}}
-				</div>
-				<div class="item text grey">
-					<span class="octicon octicon-info"></span>
-					{{$.i18n.Tr "repo.pulls.cannot_auto_merge_helper"}}
-				</div>
+				{{/* Merge conflict without specific file. Suggest manual merge, only if all reviews and status checks OK. */}}
+				{{if .IsBlockedByApprovals}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+					{{$.i18n.Tr "repo.pulls.blocked_by_approvals" .GrantedApprovals .Issue.PullRequest.ProtectedBranch.RequiredApprovals}}
+					</div>
+				{{else if .IsBlockedByRejection}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+					{{$.i18n.Tr "repo.pulls.blocked_by_rejection"}}
+					</div>
+				{{else if and .EnableStatusCheck (not .IsRequiredStatusCheckSuccess)}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+						{{$.i18n.Tr "repo.pulls.required_status_check_failed"}}
+					</div>
+				{{else}}
+					<div class="item text red">
+						<span class="octicon octicon-x"></span>
+						{{$.i18n.Tr "repo.pulls.cannot_auto_merge_desc"}}
+					</div>
+					<div class="item text grey">
+						<span class="octicon octicon-info"></span>
+						{{$.i18n.Tr "repo.pulls.cannot_auto_merge_helper"}}
+					</div>
+				{{end}}
 			{{end}}
 		</div>
 	</div>
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index d0e23a460e..ddf144066d 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -10745,6 +10745,10 @@
         },
         "MergeTitleField": {
           "type": "string"
+        },
+        "force_merge": {
+          "type": "boolean",
+          "x-go-name": "ForceMerge"
         }
       },
       "x-go-name": "MergePullRequestForm",