diff --git a/sys/kern/vfs_mount.c.vnetmnt b/sys/kern/vfs_mount.c
--- a/sys/kern/vfs_mount.c.vnetmnt
+++ b/sys/kern/vfs_mount.c
@@ -1287,7 +1287,18 @@
 	 * Only privileged root, or (if MNT_USER is set) the user that
 	 * did the original mount is permitted to update it.
 	 */
-	error = vfs_suser(mp, td);
+#ifdef VNET_NFSD
+	/*
+	 * For the case of mountd doing exports in a jail, don't
+	 * call vfs_suser().  vfs_domount() has already checked that
+	 * "root" is doing this and vfs_suser() will fail when
+	 * the file system has been mounted outside the jail.
+	 */
+	error = 0;
+	if ((fsflags & MNT_EXPORTED) == 0 || !jailed(td->td_ucred) ||
+	    !prison_check_nfsd(td->td_ucred))
+#endif
+		error = vfs_suser(mp, td);
 	if (error != 0) {
 		vput(vp);
 		return (error);
@@ -1332,7 +1343,19 @@
 	 * XXX The final recipients of VFS_MOUNT just overwrite the ndp they
 	 * get.  No freeing of cn_pnbuf.
 	 */
-	error = VFS_MOUNT(mp);
+#ifdef VNET_NFSD
+	/*
+	 * For the case of mountd doing exports from within a vnet prison,
+	 * "from" is not set correctly such that VFS_MOUNT() will return ENOENT.
+	 * It is not obvious that VFS_MOUNT() ever needs to be called when
+	 * mountd is doing exports, but this check only applies to the
+	 * specific case where it is running inside a vnet prison, for now.
+	 */
+	error = 0;
+	if ((fsflags & MNT_EXPORTED) == 0 || !jailed(td->td_ucred) ||
+	    !prison_check_nfsd(td->td_ucred))
+#endif
+		error = VFS_MOUNT(mp);
 
 	export_error = 0;
 	/* Process the export option. */
@@ -1487,6 +1510,14 @@
 	if (strlen(fstype) >= MFSNAMELEN || strlen(fspath) >= MNAMELEN)
 		return (ENAMETOOLONG);
 
+#ifdef VNET_NFSD
+	if ((fsflags & MNT_EXPORTED) != 0 && jailed(td->td_ucred) &&
+	    prison_check_nfsd(td->td_ucred)) {
+		error = priv_check(td, PRIV_NFS_DAEMON);
+		if (error)
+			return (error);
+	} else
+#endif
 	if (jailed(td->td_ucred) || usermount == 0) {
 		if ((error = priv_check(td, PRIV_VFS_MOUNT)) != 0)
 			return (error);