diff --git a/models/repo/star.go b/models/repo/star.go
index b3d3d795f8..89bdb7ac05 100644
--- a/models/repo/star.go
+++ b/models/repo/star.go
@@ -85,3 +85,17 @@ func GetStargazers(repo *Repository, opts db.ListOptions) ([]*user_model.User, e
 	users := make([]*user_model.User, 0, 8)
 	return users, sess.Find(&users)
 }
+
+// ClearRepoStars clears all stars for a repository and from the user that starred it.
+// Used when a repository is set to private.
+func ClearRepoStars(ctx context.Context, repoID int64) error {
+	if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repoID); err != nil {
+		return err
+	}
+
+	if _, err := db.Exec(ctx, "UPDATE `repository` SET num_stars = 0 WHERE id = ?", repoID); err != nil {
+		return err
+	}
+
+	return db.DeleteBeans(ctx, Star{RepoID: repoID})
+}
diff --git a/models/repo/star_test.go b/models/repo/star_test.go
index 7221a6c8eb..f15ac12ebe 100644
--- a/models/repo/star_test.go
+++ b/models/repo/star_test.go
@@ -51,3 +51,21 @@ func TestRepository_GetStargazers2(t *testing.T) {
 	assert.NoError(t, err)
 	assert.Len(t, gazers, 0)
 }
+
+func TestClearRepoStars(t *testing.T) {
+	assert.NoError(t, unittest.PrepareTestDatabase())
+	const userID = 2
+	const repoID = 1
+	unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
+	assert.NoError(t, repo_model.StarRepo(userID, repoID, true))
+	unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
+	assert.NoError(t, repo_model.StarRepo(userID, repoID, false))
+	unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
+	assert.NoError(t, repo_model.ClearRepoStars(db.DefaultContext, repoID))
+	unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID})
+
+	repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+	gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0})
+	assert.NoError(t, err)
+	assert.Len(t, gazers, 0)
+}
diff --git a/modules/repository/create.go b/modules/repository/create.go
index e1f0bdcdf9..0558d7f1c0 100644
--- a/modules/repository/create.go
+++ b/modules/repository/create.go
@@ -397,6 +397,10 @@ func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibili
 			if err != nil {
 				return err
 			}
+
+			if err = repo_model.ClearRepoStars(ctx, repo.ID); err != nil {
+				return err
+			}
 		}
 
 		// Create/Remove git-daemon-export-ok for git-daemon...
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 2245d9bae0..195252c47d 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -972,6 +972,7 @@ mirror_password_blank_placeholder = (Unset)
 mirror_password_help = Change the username to erase a stored password.
 watchers = Watchers
 stargazers = Stargazers
+stars_remove_warning = This will remove all stars from this repository.
 forks = Forks
 reactions_more = and %d more
 unit_disabled = The site administrator has disabled this repository section.
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index e54c8a23a2..809fd87dc6 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -26,7 +26,7 @@
 				{{if not .Repository.IsFork}}
 					<div class="inline field">
 						<label>{{.locale.Tr "repo.visibility"}}</label>
-						<div class="ui checkbox">
+						<div class="ui checkbox{{if and (not .Repository.IsPrivate) (gt .Repository.NumStars 0)}} tooltip{{end}}" data-content="{{.locale.Tr "repo.stars_remove_warning"}}">
 							{{if .IsAdmin}}
 							<input name="private" type="checkbox" {{if .Repository.IsPrivate}}checked{{end}}>
 							{{else}}