diff --git a/cmd/podman/common/util.go b/cmd/podman/common/util.go
index ce323a4ba8..6c8c221471 100644
--- a/cmd/podman/common/util.go
+++ b/cmd/podman/common/util.go
@@ -184,22 +184,24 @@ func parseSplitPort(hostIP, hostPort *string, ctrPort string, protocol *string)
 	}
 	if hostPort != nil {
 		if *hostPort == "" {
-			return newPort, errors.Errorf("must provide a non-empty container host port to publish")
+			// Set 0 as a placeholder. The server side of Specgen
+			// will find a random, open, unused port to use.
+			newPort.HostPort = 0
+		} else {
+			hostStart, hostLen, err := parseAndValidateRange(*hostPort)
+			if err != nil {
+				return newPort, errors.Wrapf(err, "error parsing host port")
+			}
+			if hostLen != ctrLen {
+				return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen)
+			}
+			newPort.HostPort = hostStart
 		}
-		hostStart, hostLen, err := parseAndValidateRange(*hostPort)
-		if err != nil {
-			return newPort, errors.Wrapf(err, "error parsing host port")
-		}
-		if hostLen != ctrLen {
-			return newPort, errors.Errorf("host and container port ranges have different lengths: %d vs %d", hostLen, ctrLen)
-		}
-		newPort.HostPort = hostStart
+	} else {
+		newPort.HostPort = newPort.ContainerPort
 	}
 
 	hport := newPort.HostPort
-	if hport == 0 {
-		hport = newPort.ContainerPort
-	}
 	logrus.Debugf("Adding port mapping from %d to %d length %d protocol %q", hport, newPort.ContainerPort, newPort.Range, newPort.Protocol)
 
 	return newPort, nil
diff --git a/docs/source/markdown/podman-create.1.md b/docs/source/markdown/podman-create.1.md
index ded668f34a..30ac54de2d 100644
--- a/docs/source/markdown/podman-create.1.md
+++ b/docs/source/markdown/podman-create.1.md
@@ -626,6 +626,8 @@ When specifying ranges for both, the number of container ports in the range must
 (e.g., `podman run -p 1234-1236:1222-1224 --name thisWorks -t busybox`
 but not `podman run -p 1230-1236:1230-1240 --name RangeContainerPortsBiggerThanRangeHostPorts -t busybox`)
 With ip: `podman run -p 127.0.0.1:$HOSTPORT:$CONTAINERPORT --name CONTAINER -t someimage`
+Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
+If it is not, the container port will be randomly assigned a port on the host.
 Use `podman port` to see the actual mapping: `podman port CONTAINER $CONTAINERPORT`
 
 **--publish-all**, **-P**=*true|false*
diff --git a/docs/source/markdown/podman-run.1.md b/docs/source/markdown/podman-run.1.md
index 83971107f9..2e2adbc7ee 100644
--- a/docs/source/markdown/podman-run.1.md
+++ b/docs/source/markdown/podman-run.1.md
@@ -638,6 +638,9 @@ Both hostPort and containerPort can be specified as a range of ports.
 
 When specifying ranges for both, the number of container ports in the range must match the number of host ports in the range.
 
+Host port does not have to be specified (e.g. `podman run -p 127.0.0.1::80`).
+If it is not, the container port will be randomly assigned a port on the host.
+
 Use **podman port** to see the actual mapping: **podman port $CONTAINER $CONTAINERPORT**.
 
 **--publish-all**, **-P**=**true**|**false**
diff --git a/pkg/specgen/generate/ports.go b/pkg/specgen/generate/ports.go
index 91c8e68d19..5c06d3bc30 100644
--- a/pkg/specgen/generate/ports.go
+++ b/pkg/specgen/generate/ports.go
@@ -43,6 +43,8 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
 		containerPortValidate[proto] = make(map[string]map[uint16]uint16)
 	}
 
+	postAssignHostPort := false
+
 	// Iterate through all port mappings, generating OCICNI PortMapping
 	// structs and validating there is no overlap.
 	for _, port := range portMappings {
@@ -71,9 +73,6 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
 			return nil, nil, nil, errors.Errorf("container port number must be non-0")
 		}
 		hostPort := port.HostPort
-		if hostPort == 0 {
-			hostPort = containerPort
-		}
 		if uint32(len-1)+uint32(containerPort) > 65535 {
 			return nil, nil, nil, errors.Errorf("container port range exceeds maximum allowable port number")
 		}
@@ -105,26 +104,42 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
 				cPort := containerPort + index
 				hPort := hostPort + index
 
-				if cPort == 0 || hPort == 0 {
-					return nil, nil, nil, errors.Errorf("host and container ports cannot be 0")
+				if cPort == 0 {
+					return nil, nil, nil, errors.Errorf("container port cannot be 0")
 				}
 
-				testCPort := ctrPortMap[cPort]
-				if testCPort != 0 && testCPort != hPort {
-					// This is an attempt to redefine a port
-					return nil, nil, nil, errors.Errorf("conflicting port mappings for container port %d (protocol %s)", cPort, p)
-				}
-				ctrPortMap[cPort] = hPort
+				// Host port is allowed to be 0. If it is, we
+				// select a random port on the host.
+				// This will happen *after* all other ports are
+				// placed, to ensure we don't accidentally
+				// select a port that a later mapping wanted.
+				if hPort == 0 {
+					// If we already have a host port
+					// assigned to their container port -
+					// just use that.
+					if ctrPortMap[cPort] != 0 {
+						hPort = ctrPortMap[cPort]
+					} else {
+						postAssignHostPort = true
+					}
+				} else {
+					testCPort := ctrPortMap[cPort]
+					if testCPort != 0 && testCPort != hPort {
+						// This is an attempt to redefine a port
+						return nil, nil, nil, errors.Errorf("conflicting port mappings for container port %d (protocol %s)", cPort, p)
+					}
+					ctrPortMap[cPort] = hPort
 
-				testHPort := hostPortMap[hPort]
-				if testHPort != 0 && testHPort != cPort {
-					return nil, nil, nil, errors.Errorf("conflicting port mappings for host port %d (protocol %s)", hPort, p)
-				}
-				hostPortMap[hPort] = cPort
+					testHPort := hostPortMap[hPort]
+					if testHPort != 0 && testHPort != cPort {
+						return nil, nil, nil, errors.Errorf("conflicting port mappings for host port %d (protocol %s)", hPort, p)
+					}
+					hostPortMap[hPort] = cPort
 
-				// If we have an exact duplicate, just continue
-				if testCPort == hPort && testHPort == cPort {
-					continue
+					// If we have an exact duplicate, just continue
+					if testCPort == hPort && testHPort == cPort {
+						continue
+					}
 				}
 
 				// We appear to be clear. Make an OCICNI port
@@ -142,6 +157,61 @@ func parsePortMapping(portMappings []specgen.PortMapping) ([]ocicni.PortMapping,
 		}
 	}
 
+	// Handle any 0 host ports now by setting random container ports.
+	if postAssignHostPort {
+		remadeMappings := make([]ocicni.PortMapping, 0, len(finalMappings))
+
+		// Iterate over all
+		for _, p := range finalMappings {
+			if p.HostPort != 0 {
+				remadeMappings = append(remadeMappings, p)
+				continue
+			}
+
+			hostIPMap := hostPortValidate[p.Protocol]
+			ctrIPMap := containerPortValidate[p.Protocol]
+
+			hostPortMap, ok := hostIPMap[p.HostIP]
+			if !ok {
+				hostPortMap = make(map[uint16]uint16)
+				hostIPMap[p.HostIP] = hostPortMap
+			}
+			ctrPortMap, ok := ctrIPMap[p.HostIP]
+			if !ok {
+				ctrPortMap = make(map[uint16]uint16)
+				ctrIPMap[p.HostIP] = ctrPortMap
+			}
+
+			// See if container port has been used elsewhere
+			if ctrPortMap[uint16(p.ContainerPort)] != 0 {
+				// Duplicate definition. Let's not bother
+				// including it.
+				continue
+			}
+
+			// Max retries to ensure we don't loop forever.
+			for i := 0; i < 15; i++ {
+				candidate, err := getRandomPort()
+				if err != nil {
+					return nil, nil, nil, errors.Wrapf(err, "error getting candidate host port for container port %d", p.ContainerPort)
+				}
+
+				if hostPortMap[uint16(candidate)] == 0 {
+					logrus.Debugf("Successfully assigned container port %d to host port %d (IP %s Protocol %s)", p.ContainerPort, candidate, p.HostIP, p.Protocol)
+					hostPortMap[uint16(candidate)] = uint16(p.ContainerPort)
+					ctrPortMap[uint16(p.ContainerPort)] = uint16(candidate)
+					p.HostPort = int32(candidate)
+					break
+				}
+			}
+			if p.HostPort == 0 {
+				return nil, nil, nil, errors.Errorf("could not find open host port to map container port %d to", p.ContainerPort)
+			}
+			remadeMappings = append(remadeMappings, p)
+		}
+		return remadeMappings, containerPortValidate, hostPortValidate, nil
+	}
+
 	return finalMappings, containerPortValidate, hostPortValidate, nil
 }
 
diff --git a/pkg/specgen/specgen.go b/pkg/specgen/specgen.go
index 3d5bf03e5f..361f09379f 100644
--- a/pkg/specgen/specgen.go
+++ b/pkg/specgen/specgen.go
@@ -435,7 +435,8 @@ type PortMapping struct {
 	ContainerPort uint16 `json:"container_port"`
 	// HostPort is the port number that will be forwarded from the host into
 	// the container.
-	// If omitted, will be assumed to be identical to
+	// If omitted, a random port on the host (guaranteed to be over 1024)
+	// will be assigned.
 	HostPort uint16 `json:"host_port,omitempty"`
 	// Range is the number of ports that will be forwarded, starting at
 	// HostPort and ContainerPort and counting up.
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index afba12ccd5..cdfbd55306 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -184,6 +184,30 @@ var _ = Describe("Podman run networking", func() {
 		Expect(inspectOut[0].NetworkSettings.Ports["80/tcp"][0].HostIP).To(Equal(""))
 	})
 
+	It("podman run -p 127.0.0.1::8080/udp", func() {
+		name := "testctr"
+		session := podmanTest.Podman([]string{"create", "-t", "-p", "127.0.0.1::8080/udp", "--name", name, ALPINE, "/bin/sh"})
+		session.WaitWithDefaultTimeout()
+		inspectOut := podmanTest.InspectContainer(name)
+		Expect(len(inspectOut)).To(Equal(1))
+		Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+		Expect(len(inspectOut[0].NetworkSettings.Ports["8080/udp"])).To(Equal(1))
+		Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostPort).To(Not(Equal("8080")))
+		Expect(inspectOut[0].NetworkSettings.Ports["8080/udp"][0].HostIP).To(Equal("127.0.0.1"))
+	})
+
+	It("podman run -p :8080", func() {
+		name := "testctr"
+		session := podmanTest.Podman([]string{"create", "-t", "-p", ":8080", "--name", name, ALPINE, "/bin/sh"})
+		session.WaitWithDefaultTimeout()
+		inspectOut := podmanTest.InspectContainer(name)
+		Expect(len(inspectOut)).To(Equal(1))
+		Expect(len(inspectOut[0].NetworkSettings.Ports)).To(Equal(1))
+		Expect(len(inspectOut[0].NetworkSettings.Ports["8080/tcp"])).To(Equal(1))
+		Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostPort).To(Not(Equal("8080")))
+		Expect(inspectOut[0].NetworkSettings.Ports["8080/tcp"][0].HostIP).To(Equal(""))
+	})
+
 	It("podman run network expose host port 80 to container port 8000", func() {
 		SkipIfRootless()
 		session := podmanTest.Podman([]string{"run", "-dt", "-p", "80:8000", ALPINE, "/bin/sh"})