diff --git a/docs/reference/commandline/pause.md b/docs/reference/commandline/pause.md
index 629c6ed091..6e85ebbea0 100644
--- a/docs/reference/commandline/pause.md
+++ b/docs/reference/commandline/pause.md
@@ -19,11 +19,12 @@ Options:
       --help   Print usage
 ```
 
-The `docker pause` command uses the cgroups freezer to suspend all processes in
-a container. Traditionally, when suspending a process the `SIGSTOP` signal is
-used, which is observable by the process being suspended. With the cgroups freezer
-the process is unaware, and unable to capture, that it is being suspended,
-and subsequently resumed.
+The `docker pause` command suspends all processes in a container. On Linux,
+this uses the cgroups freezer. Traditionally, when suspending a process the
+`SIGSTOP` signal is used, which is observable by the process being suspended.
+With the cgroups freezer the process is unaware, and unable to capture,
+that it is being suspended, and subsequently resumed. On Windows, only Hyper-V
+containers can be paused.
 
 See the
 [cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)
diff --git a/docs/reference/commandline/unpause.md b/docs/reference/commandline/unpause.md
index e5c9d506e0..9795f16482 100644
--- a/docs/reference/commandline/unpause.md
+++ b/docs/reference/commandline/unpause.md
@@ -19,8 +19,8 @@ Options:
       --help   Print usage
 ```
 
-The `docker unpause` command uses the cgroups freezer to un-suspend all
-processes in a container.
+The `docker unpause` command un-suspends all processes in a container.
+On Linux, it does this using the cgroups freezer.
 
 See the
 [cgroups freezer documentation](https://www.kernel.org/doc/Documentation/cgroup-v1/freezer-subsystem.txt)
diff --git a/integration-cli/docker_cli_attach_test.go b/integration-cli/docker_cli_attach_test.go
index 08f6119779..2df4fdc4d2 100644
--- a/integration-cli/docker_cli_attach_test.go
+++ b/integration-cli/docker_cli_attach_test.go
@@ -154,9 +154,9 @@ func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
 }
 
 func (s *DockerSuite) TestAttachPausedContainer(c *check.C) {
-	testRequires(c, DaemonIsLinux) // Containers cannot be paused on Windows
+	testRequires(c, IsPausable)
 	defer unpauseAllContainers()
-	dockerCmd(c, "run", "-d", "--name=test", "busybox", "top")
+	runSleepingContainer(c, "-d", "--name=test")
 	dockerCmd(c, "pause", "test")
 
 	result := dockerCmdWithResult("attach", "test")
diff --git a/integration-cli/docker_cli_exec_test.go b/integration-cli/docker_cli_exec_test.go
index d0be69bfa0..da815335b0 100644
--- a/integration-cli/docker_cli_exec_test.go
+++ b/integration-cli/docker_cli_exec_test.go
@@ -127,11 +127,10 @@ func (s *DockerSuite) TestExecExitStatus(c *check.C) {
 }
 
 func (s *DockerSuite) TestExecPausedContainer(c *check.C) {
-	// Windows does not support pause
-	testRequires(c, DaemonIsLinux)
+	testRequires(c, IsPausable)
 	defer unpauseAllContainers()
 
-	out, _ := dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
+	out, _ := runSleepingContainer(c, "-d", "--name", "testing")
 	ContainerID := strings.TrimSpace(out)
 
 	dockerCmd(c, "pause", "testing")
diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go
index 63171117b4..c0caa23556 100644
--- a/integration-cli/docker_cli_info_test.go
+++ b/integration-cli/docker_cli_info_test.go
@@ -138,9 +138,9 @@ func (s *DockerSuite) TestInfoDisplaysRunningContainers(c *check.C) {
 }
 
 func (s *DockerSuite) TestInfoDisplaysPausedContainers(c *check.C) {
-	testRequires(c, DaemonIsLinux)
+	testRequires(c, IsPausable)
 
-	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
+	out, _ := runSleepingContainer(c, "-d")
 	cleanedContainerID := strings.TrimSpace(out)
 
 	dockerCmd(c, "pause", cleanedContainerID)
diff --git a/integration-cli/docker_cli_pause_test.go b/integration-cli/docker_cli_pause_test.go
index e546ad45d5..9217a69968 100644
--- a/integration-cli/docker_cli_pause_test.go
+++ b/integration-cli/docker_cli_pause_test.go
@@ -8,11 +8,11 @@ import (
 )
 
 func (s *DockerSuite) TestPause(c *check.C) {
-	testRequires(c, DaemonIsLinux)
+	testRequires(c, IsPausable)
 	defer unpauseAllContainers()
 
 	name := "testeventpause"
-	dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
+	runSleepingContainer(c, "-d", "--name", name)
 
 	dockerCmd(c, "pause", name)
 	pausedContainers, err := getSliceOfPausedContainers()
@@ -30,7 +30,7 @@ func (s *DockerSuite) TestPause(c *check.C) {
 }
 
 func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
-	testRequires(c, DaemonIsLinux)
+	testRequires(c, IsPausable)
 	defer unpauseAllContainers()
 
 	containers := []string{
@@ -38,7 +38,7 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
 		"testpausewithmorecontainers2",
 	}
 	for _, name := range containers {
-		dockerCmd(c, "run", "-d", "--name", name, "busybox", "top")
+		runSleepingContainer(c, "-d", "--name", name)
 	}
 	dockerCmd(c, append([]string{"pause"}, containers...)...)
 	pausedContainers, err := getSliceOfPausedContainers()
@@ -58,9 +58,9 @@ func (s *DockerSuite) TestPauseMultipleContainers(c *check.C) {
 	}
 }
 
-func (s *DockerSuite) TestPauseFailsOnWindows(c *check.C) {
-	testRequires(c, DaemonIsWindows)
-	dockerCmd(c, "run", "-d", "--name=test", "busybox", "sleep 3")
+func (s *DockerSuite) TestPauseFailsOnWindowsServerContainers(c *check.C) {
+	testRequires(c, DaemonIsWindows, NotPausable)
+	runSleepingContainer(c, "-d", "--name=test")
 	out, _, _ := dockerCmdWithError("pause", "test")
-	c.Assert(out, checker.Contains, "Windows: Containers cannot be paused")
+	c.Assert(out, checker.Contains, "cannot pause Windows Server Containers")
 }
diff --git a/integration-cli/docker_cli_start_test.go b/integration-cli/docker_cli_start_test.go
index f96528f7d6..b1cea35872 100644
--- a/integration-cli/docker_cli_start_test.go
+++ b/integration-cli/docker_cli_start_test.go
@@ -95,10 +95,10 @@ func (s *DockerSuite) TestStartRecordError(c *check.C) {
 
 func (s *DockerSuite) TestStartPausedContainer(c *check.C) {
 	// Windows does not support pausing containers
-	testRequires(c, DaemonIsLinux)
+	testRequires(c, IsPausable)
 	defer unpauseAllContainers()
 
-	dockerCmd(c, "run", "-d", "--name", "testing", "busybox", "top")
+	runSleepingContainer(c, "-d", "--name", "testing")
 
 	dockerCmd(c, "pause", "testing")
 
diff --git a/integration-cli/requirements.go b/integration-cli/requirements.go
index bba6f815f8..53ec417f13 100644
--- a/integration-cli/requirements.go
+++ b/integration-cli/requirements.go
@@ -201,6 +201,24 @@ var (
 		},
 		"Test cannot be run when remapping root",
 	}
+	IsPausable = testRequirement{
+		func() bool {
+			if daemonPlatform == "windows" {
+				return isolation == "hyperv"
+			}
+			return true
+		},
+		"Test requires containers are pausable.",
+	}
+	NotPausable = testRequirement{
+		func() bool {
+			if daemonPlatform == "windows" {
+				return isolation == "process"
+			}
+			return false
+		},
+		"Test requires containers are not pausable.",
+	}
 )
 
 // testRequires checks if the environment satisfies the requirements
diff --git a/libcontainerd/client_windows.go b/libcontainerd/client_windows.go
index da30ced86b..a03ffd9595 100644
--- a/libcontainerd/client_windows.go
+++ b/libcontainerd/client_windows.go
@@ -447,12 +447,81 @@ func (clnt *client) Resize(containerID, processFriendlyName string, width, heigh
 
 // Pause handles pause requests for containers
 func (clnt *client) Pause(containerID string) error {
-	return errors.New("Windows: Containers cannot be paused")
+	unlockContainer := true
+	// Get the libcontainerd container object
+	clnt.lock(containerID)
+	defer func() {
+		if unlockContainer {
+			clnt.unlock(containerID)
+		}
+	}()
+	container, err := clnt.getContainer(containerID)
+	if err != nil {
+		return err
+	}
+
+	for _, option := range container.options {
+		if h, ok := option.(*HyperVIsolationOption); ok {
+			if !h.IsHyperV {
+				return errors.New("cannot pause Windows Server Containers")
+			}
+			break
+		}
+	}
+
+	err = container.hcsContainer.Pause()
+	if err != nil {
+		return err
+	}
+
+	// Unlock container before calling back into the daemon
+	unlockContainer = false
+	clnt.unlock(containerID)
+
+	return clnt.backend.StateChanged(containerID, StateInfo{
+		CommonStateInfo: CommonStateInfo{
+			State: StatePause,
+		}})
 }
 
 // Resume handles resume requests for containers
 func (clnt *client) Resume(containerID string) error {
-	return errors.New("Windows: Containers cannot be paused")
+	unlockContainer := true
+	// Get the libcontainerd container object
+	clnt.lock(containerID)
+	defer func() {
+		if unlockContainer {
+			clnt.unlock(containerID)
+		}
+	}()
+	container, err := clnt.getContainer(containerID)
+	if err != nil {
+		return err
+	}
+
+	// This should never happen, since Windows Server Containers cannot be paused
+	for _, option := range container.options {
+		if h, ok := option.(*HyperVIsolationOption); ok {
+			if !h.IsHyperV {
+				return errors.New("cannot resume Windows Server Containers")
+			}
+			break
+		}
+	}
+
+	err = container.hcsContainer.Resume()
+	if err != nil {
+		return err
+	}
+
+	// Unlock container before calling back into the daemon
+	unlockContainer = false
+	clnt.unlock(containerID)
+
+	return clnt.backend.StateChanged(containerID, StateInfo{
+		CommonStateInfo: CommonStateInfo{
+			State: StateResume,
+		}})
 }
 
 // Stats handles stats requests for containers
diff --git a/man/docker-pause.1.md b/man/docker-pause.1.md
index 5d2267af62..ffc3b35ca0 100644
--- a/man/docker-pause.1.md
+++ b/man/docker-pause.1.md
@@ -10,11 +10,12 @@ CONTAINER [CONTAINER...]
 
 # DESCRIPTION
 
-The `docker pause` command uses the cgroups freezer to suspend all processes in
-a container.  Traditionally when suspending a process the `SIGSTOP` signal is
-used, which is observable by the process being suspended. With the cgroups freezer
-the process is unaware, and unable to capture, that it is being suspended,
-and subsequently resumed.
+The `docker pause` command suspends all processes in a container. On Linux,
+this uses the cgroups freezer. Traditionally, when suspending a process the
+`SIGSTOP` signal is used, which is observable by the process being suspended.
+With the cgroups freezer the process is unaware, and unable to capture,
+that it is being suspended, and subsequently resumed. On Windows, only Hyper-V
+containers can be paused.
 
 See the [cgroups freezer documentation]
 (https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for
diff --git a/man/docker-unpause.1.md b/man/docker-unpause.1.md
index 466e1bb1a3..8c64e68de6 100644
--- a/man/docker-unpause.1.md
+++ b/man/docker-unpause.1.md
@@ -10,8 +10,8 @@ CONTAINER [CONTAINER...]
 
 # DESCRIPTION
 
-The `docker unpause` command uses the cgroups freezer to un-suspend all
-processes in a container.
+The `docker unpause` command un-suspends all processes in a container.
+On Linux, it does this using the cgroups freezer.
 
 See the [cgroups freezer documentation]
 (https://www.kernel.org/doc/Documentation/cgroups/freezer-subsystem.txt) for